日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

回归本心QwQ背包问题luogu1776

發(fā)布時(shí)間:2023/12/20 编程问答 47 豆豆
生活随笔 收集整理的這篇文章主要介紹了 回归本心QwQ背包问题luogu1776 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

今天在這里說一下多重背包問題 對(duì)

之前一直沒有怎么徹底理解

首先多重背包是什么?這里就不做過多的贅述了

樸素的多重背包的復(fù)雜度是\(O(n*m*\sum s[i])\),其中\(s[i]\)是每一件物品的數(shù)量

for (int i=1;i<=n;i++)for (int k=1;k<=s[i];k++)for (int j=m;j>=k*c[i];j--)dp[j]=max(dp[j],dp[j-k*c[i]]+k*w[i]);

但大多數(shù)題目,這種復(fù)雜度是不能允許的

那么我們考慮優(yōu)化

首先我們考慮,怎么樣快速表示\(1~n\)中所有的數(shù)呢?

二進(jìn)制!

打個(gè)比方\(n=6\),那么我們就只需要1 2 3就能構(gòu)成所有的數(shù)

1=1
2=2
3=3
4=1+3
5=2+3
6=1+2+3

對(duì)于一個(gè)數(shù)n,我們只需要從小開始不停用n減去2的冪次方,若n大于0,則當(dāng)前的二的冪次方合法,最后我們將合法的二的冪次方和最后的余數(shù)分別看成一個(gè)新的物品去做背包,就能表示出所有的\(1~n\)的數(shù)(可以理解為,小于n的數(shù)的二進(jìn)制,一定不會(huì)比n大,那么構(gòu)成n的這些二進(jìn)制位,一定是夠用的)

那么我們只需要對(duì)\(s[i]\)進(jìn)行二進(jìn)制拆分,然后把他們看成一個(gè)物品

直接上代碼

#include<iostream> #include<cstdio> #include<algorithm> #include<cstring> #include<cmath> #include<queue>using namespace std;inline int read() {int x=0,f=1;char ch=getchar();while (!isdigit(ch)) {if (ch=='-') f=-1;ch=getchar();}while (isdigit(ch)) {x=(x<<1)+(x<<3)+ch-'0';ch=getchar();}return x*f; }const int maxn = 2e5+1e2;int f[maxn]; int n,m; int c[maxn],w[maxn]; int tmp ; int main() {n=read(),m=read();for (int i=1;i<=n;i++){int y=read(),z=read(),x=read();int inv = 1;while (x){inv=min(inv,x);w[++tmp]=inv*y;c[tmp]=inv*z;x-=inv;inv<<=1;}}//for (int i=1;i<=tmp;i++) comemset(f,0xdf,sizeof(f));f[0]=0;for (int i=1;i<=tmp;i++){for (int j=m;j>=c[i];j--){f[j]=max(f[j],f[j-c[i]]+w[i]);}}int ans=-1e9;for (int i=1;i<=m;i++) ans=max(ans,f[i]);cout<<ans;return 0; }

QwQ 二進(jìn)制優(yōu)化的復(fù)雜度是\(O(nlogn\times m)\)

然而,我們可以用單調(diào)隊(duì)列做到\(O(nm)\)的(雖然據(jù)說常數(shù)很大)

這里比較懶,直接放一個(gè)dalao的博客了

我就寫幾點(diǎn)自己的理解吧:

首先,我們是枚舉體積的余數(shù)和倍數(shù),然后轉(zhuǎn)移
維護(hù)單調(diào)隊(duì)列的時(shí)候,一定要注意維護(hù)隊(duì)首元素過期
雖然我也不知到這種算法的正確性,不過它運(yùn)用的思路就是把同樣的余數(shù)\(m'\),放到一起考慮對(duì)

直接上代碼

#include<iostream> #include<cstdio> #include<algorithm> #include<cstring> #include<cmath>using namespace std;inline int read() {int x=0,f=1;char ch=getchar();while (!isdigit(ch)){if (ch=='-') f=-1;ch=getchar();}while (isdigit(ch)){x=(x<<1)+(x<<3)+ch-'0';ch=getchar();}return x*f; }const int maxn = 2e5+1e2;int q[maxn],t[maxn]; int head=1,tail=0;void push(int x,int pos,int p) {while (head<=tail && x>=q[tail])q[tail]=0,t[tail--]=0;q[++tail]=x;t[tail]=pos; while (head<tail && t[head]<pos-p) head++; }int c[maxn],w[maxn],s[maxn]; int n,m; int f[110][maxn];int main() {n=read(),m=read();for (int i=1;i<=n;i++) w[i]=read(),c[i]=read(),s[i]=read();for (int i=1;i<=n;i++){//if (c[i]==0) while (1); int kk = m/c[i]; //int num = min(s[i],kk); //最多能放多少個(gè) for (int j=0;j<c[i];j++) //枚舉余數(shù) {head=1,tail=0;int ymh = (m-j)/c[i];for (int k=0;k<=ymh;k++){push(f[i-1][j+k*c[i]]-k*w[i],k,num);f[i][j+k*c[i]]=max(f[i][j+k*c[i]],q[head]+k*w[i]);}}}int ans=-1e9;//for (int i=0;i<=m;i++) ans=max(ans,f[n][i]);for (int i=1;i<=n;i++)for (int j=1;j<=m;j++) ans=max(ans,f[i][j]);cout<<ans;return 0; }

轉(zhuǎn)載于:https://www.cnblogs.com/yimmortal/p/10160850.html

總結(jié)

以上是生活随笔為你收集整理的回归本心QwQ背包问题luogu1776的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。