揹包問題 DP

2021-09-12 07:04:27 字數 2867 閱讀 8050

01揹包

現在有1個體積為mmax的揹包和n種物品(每種物品只有1個)。每種物品的體積和價值分別是v[i]和w[i]。求這個揹包最多可以裝價值多少的物品。

這是最基礎的揹包問題,特點是:每種物品僅有一件,可以選擇放或不放。

用子問題定義狀態:設f[i][j]表示前i件物品恰放入乙個容量為j的揹包可以獲得的最大價值。

我們依次遍歷,到了第i件物品了

如果還能放的下這件物品我們就要考慮,到底是放入還是不放入這件物品會差生最大價值呢,我們需要做乙個比較,也就是

解釋一下f[i-1][j]是不放入這件物品,f[i-1]j-v[i]+w[i]是放入這件物品(這件物品的價值+前i-1件,體積減少了這件物品的揹包中的價值)

模板如下

#define n 10010

int v[n],w[n]; //每件物品的體積和價值

int n,mmax; //物品種類數 以及 揹包體積

int f[n][n]; //dp陣列

for(int i=1;i<=n;i++) cin>>v[i]>>w[i]; //提倡從1開始輸入

for(int i=1;i<=n;i++)

for(int j=0;j<=mmax;j++)

cout《完全揹包

現在有1個體積為mmax的揹包和n種物品(每種物品有無限個)。每種物品的體積和價值分別是v[i]和w[i]。求這個揹包最多可以裝價值多少的物品。

這是最基礎的揹包問題,特點是:每種物品有無限個,可以選擇放葉可以選擇不放,選擇放的時候可以放多個。

用子問題定義狀態:設f[i][j]表示前i件物品恰放入乙個容量為j的揹包可以獲得的最大價值。

我們依次遍歷,到了第i件物品了

模板如下

#define n 10010

int v[n],w[n]; //每件物品的體積和價值

int n,mmax; //物品種類數 以及 揹包體積

int f[n][n]; //dp陣列

for(int i=1;i<=n;i++) cin>>v[i]>>w[i]; //提倡從1開始輸入

for(int i=1;i<=n;i++)

for(int j=0;j<=mmax;j++)

for(int k=0;k*v[i]<=j;k++)

cout《通常我們不用上述模板嗎,而是採用優化後的模板,如下

優化思路: 轉化為01揹包問題求解

既然01揹包問題是最基本的揹包問題,那麼我們可以考慮把完全揹包問題轉化為01揹包問題來解。最簡單的想法是,考慮到第i種物品最多選mmax/v[i]件,於是可以把第i種物品轉化為mmax/v[i]件體積及價值均不變的物品,然後求解這個01揹包問題。這樣完全沒有改進基本思路的時間複雜度,但這畢竟給了我們將完全揹包問題轉化為01揹包問題的思路:將一種物品拆成多件物品。

更高效的轉化方法是:把第i種物品拆成體積為v[i]*2^k、價值為w[i]*2^k的若干件物品,其中k滿足v[i]*2^k<=mmax。這是二進位制的思想,因為不管最優策略選幾件第i種物品,總可以表示成若干個2^k件物品的和。這樣把每種物品拆成o(log(mmax/v[i]))件物品,是乙個很大的改進。

**:#define n 10010

int v[n],w[n]; //每件物品的體積和價值

int n,mmax; //物品種類數 以及 揹包體積

int f[n]; //dp陣列

for(int i=1;i<=n;i++) cin>>v[i]>>w[i]; //提倡從1開始輸入

for(int i=1;i<=n;i++)

for(int j=v[i];j<=mmax;j++)

f[j]=max(f[j],f[j-v[i]]+w[i]);

cout《多重揹包

有n種物品和乙個容量為v的揹包。第i種物品最多有n[i]件可用,每件費用是c[i],價值是w[i]。求解將哪些物品裝入揹包可使這些物品的費用總和不超過揹包容量,且價值總和最大。

這題目和完全揹包問題很類似。基本的方程只需將完全揹包問題的方程略微一改即可,因為對於第i種物品有n[i]+1種策略:取0件,取1件……取n[i]件。

模板如下

#define n 10010

int v[n],w[n],num[n]; //每件物品的體積和價值以及數量

int n,mmax; //物品種類數 以及 揹包體積

int f[n]; //dp陣列

for(int i=1;i<=n;i++) cin>>v[i] >>w[i]>>num[i];

for(int i=1;i<=n;i++)

for(int j=mmax;j>=0;j--)

for(int k=0;k<=n[i];k++)

cout《優化後模板

#define n 10010

int v[n],w[n],num[n]; //每件物品的體積和價值以及數量

int n,mmax; //物品種類數 以及 揹包體積

int f[n]; //dp陣列

for(int i=1;i<=n;i++) cin>>v[i] >>w[i]>>num[i];

int k = n + 1;

for(int i=1;i<=n;i++)

}for(int i=1;i<=k;i++)

for(int j=m; j>=1;j--)

if (v[i]<=j) f[j]=max(f[j],f[j-v[i]]+w[i]);

cout《部分參考自

DP 揹包問題

大牛 以下使用滾到陣列 若輸入要求一般,可以邊定義狀態邊輸入,不需儲存 memset f,0,sizeof int n 若求最小值,除 f 0 其餘初始化為 inf,f 0 0是必須的 求最大最小都一樣 確保有從無到有的起點 0 1揹包 一般形式 f i v max f i 1 v f i 1 v ...

DP 揹包問題

小明同學在參加一場考試,考試時間2個小時。試卷上一共有n道題目,小明要在規定時間內,完成一定數量的題目。考試中不限制試題作答順序,對於 i 第道題目,小明有三種不同的策略可以選擇 1 直接跳過這道題目,不花費時間,本題得0分。2 只做一部分題目,花費pi分鐘的時間,本題可以得到ai分。3 做完整個題...

dp 揹包問題

乙個揹包總容量為v,現在有n個物品,第i個物品容量為weight i 價值為value i 現在往揹包裡面裝東西,怎樣裝才能使揹包內物品總價值最大.主要分為3類 總體的,又分為揹包剛好裝滿,與揹包沒有裝滿兩種情況 每種物品都只有1個,只有選擇與不選擇兩種狀態 有n件物品和乙個容量為v的揹包,每種物品...