多重揹包:n個物品,揹包承重m,每個物品 重量:wi 價值vi 個數為ci
普通多重揹包複雜度:o(nmc)
**:
for
(int i=
1;i<=n;i++
)for
(int j=
1;j<=m;j++
)for
(int k=
1;k<=c[i]
&& k*w[i]
<=j;k++
) f[i]
[j]=
max(f[i]
[j],f[i-1]
[j-k*w[i]
]+k*v[i]
);
單調佇列優化的多重揹包複雜度:o(nm)
考慮把o(c )的轉移壓縮為o(1)
變形:a=j/w[i]
b=j%w[i]
j=b+aw[i]
思路:承重為j時,不考慮ci限制時最多選a個i號元素。假設a個中不選k個,即選a-k個。
轉移方程:
f[i]
[j]=
max(f[i]
[j],f[i-1]
[j-(a-k)
*w[i]]+
(a-k)
*v[i]);
等價於f[i]
[j]=
max(f[i]
[j],f[i-1]
[b+k*w[i]]+
(a-k)
*v[i]);
即是f[i]
[j]=
max(f[i]
[j],f[i-1]
[b+k*w[i]
]-k*v[i]
)+a*v[i]
;//(a-k<=c[i])
這樣max裡面就與j無關了,只與b和k有關。
那麼我們列舉b和k就行了。然後用單調佇列維護max。
b+a*w[i]即為j恰好可以表示1~m的所有數
求f[i][j]用到哪些狀態,我來列舉下就一目了然了
f[i]
[b+0
*w[i]]=
max(f[i-1]
[b+0
*w[i]]-
0*v[i])+
0*v[i]
;f[i]
[b+1
*w[i]]=
max(f[i-1]
[b+0
*w[i]]-
0*v[i]
,f[i-1]
[b+1
*[w[i]])
-1*v[i])+
1*v[i]
;f[i]
[b+2
*w[i]]=
max(f[i-1]
[b+0
*w[i]]-
0*v[i]
,f[i-1]
[b+1
*[w[i]])
-1*v[i]
,f[i-1]
[b+2
*w[i]]-
2*v[i]])
+2*v[i];.
...f[i]
[b+k*w[i]]=
max(f[i-1]
[b+0
*w[i]]-
0*v[i]
,f[i-1]
[b+1
*[w[i]])
-1*v[i]
,f[i-1]
[b+2
*w[i]]-
2*v[i]].
...f[i-1]
[b+a*w[i]
]-k*v[i]
)+k*v[i];.
...f[i]
[b+a*w[i]]=
max(f[i-1]
[b+0
*w[i]]-
0*v[i]
,f[i-1]
[b+1
*[w[i]])
-1*v[i]
,f[i-1]
[b+2
*w[i]]-
2*v[i]].
...f[i-1]
[b+a*w[i]
]-a*v[i]
)+a*v[i]
;
可以發現f[i][b+k*w[i]]的轉移規律,我們就拿單調佇列把max裡的東西存下來,這樣就不用每次列舉選多少個i號物品了
**片:
for
(int b=
0; b; b++
)}
例題:hdu2191
#include
using namespace std;
#define n 110
#define inf 999999999
int t,n,m,w[n]
,v[n]
,c[n]
,ans,he,ta;
int f[n]
[7005
],q[
7005
],num[
7005];
intmain()
}}printf
("%d\n"
,f[n]
[m]);}
return0;
}
多重揹包單調佇列優化思路 單調佇列優化多重揹包問題
6.多重揹包問題 iii acwing題庫 www.acwing.com 揹包九講bilibili www.bilibili.com 從公式中可以看出f j 和f j c 都是從s 1個數裡面取最大值,計算f j c 時只是將滑動視窗右移了一步,類似下圖的效果 只不過移動的時候,前面的s個元素都增加...
單調佇列優化多重揹包
多重揹包的最原始的狀態轉移方程 令 c i min num i j v i f i j max f i 1 j k v i k w i 1 k c i 這裡的 k 是指取第 i 種物品 k 件。如果令 a j v i b j v i 那麼 j a v i b.這裡用 k 表示的意義改變,k 表示取第...
單調佇列優化多重揹包
應該是個經典演算法,稍微記錄一下 用 w i 表示重量,v i 表示價值 那麼不難寫出轉移方程 f i j max f i 1 j k w i k v i 考慮用單調佇列優化。我們若要用單調佇列優化,那麼必須滿足轉移時所需要的狀態只與 k 有關 這裡要用到乙個神仙操作,對 j w i 分類 因為對於...