一 揹包問題
(1)01 揹包 :
給定 n 種物品和乙個容量為 c 的揹包,物品 i 的重量是 wi,其價值為 vi 。
問:應該如何選擇裝入揹包的物品,使得裝入揹包中的物品的總價值最大?
分析:對於每個物品,我們都有兩種選擇,取和不取。
我們可以定義乙個二維陣列dp[i][j],表示有i件物品,揹包容量為j時獲得的最大價值。
對於dp[i][j],當w[i]>j時,dp[i][j] = dp[i-1][j];否者,dp[i][j] = max(dp[i-1][j],dp[i-1][j-w[i]]+v[i]);再放與不放中選著價值 最大的。得狀態轉移方程:
if (揹包體積j小於物品i的體積)
f[i][j] = f[i-1][j] //揹包裝不下第i個物體,目前只能靠前i-1個物體裝包
else
f[i][j] = max(f[i-1][j], f[i-1][j-wi] + vi)
我們可以把這個過程看成填乙個表
例如:價值陣列v = ,
重量陣列w = ,
揹包容量c = 12時對應的dp[i][j]陣列。01
2345
6789
1011121
0008
8888
8888
2000
881010
1010
1818183
0668
8141416
1618
182440
6699
1414
1717
1919245
0669
9141417
1719
212462
68911
1416
1719
1921
24(第一行和第一列為序號,其數值為0)
如m[2][6],在面對第二件物品,揹包容量為6時我們可以選擇不拿,那麼獲得價值僅為第一件物品的價值8,如果拿,就要把第一件物品拿出來,放第二件物品,價值10,那我們當然是選擇拿。m[2][6]=m[1][0]+10=0+10=10;依次類推,得到m[6][12]就是考慮所有物品,揹包容量為c時的最大價值。
偽**:
int w[maxn] = ;
int v[maxn] = ;
memset(dp,0,sizeof(dp));
for(int i = 1 ; i <= n ;i ++ );
int v[maxn] = ;
memset(dp,0,sizeof(dp));
for (int i = 1;i <= n;i++)
} cout<**分析:
dp陣列是從上到下,從右到左計算的,再計算(i,j)的時候,dp[j]裡儲存的就是dp(i-1,j)的值,而dp[j-w]裡儲存的是
dp(i-1,j-w)而不是dp(i,j-w)——因為dp是逆序列舉的,此時的dp(i,j-w)還沒有算出來。這樣,
dp[j] = max(dp[j],dp[j - w[i]] + v[i])實際上是把max(dp(i-1,j),dp(i-1,j-w))儲存在dp[j]中,覆蓋掉dp[j]原來的dp(i-1,j);
(2)完全揹包
有n種物品和乙個容量為v的揹包。第i種物品有若干件可用,每件費用是c[i],價值是w[i]。求解將哪些物品裝入揹包可使這些物品的費用總和不超過揹包容量,且價值總和最大。
分析:這個問題是01揹包的公升級版,不同的地方是一種物品可以放很多件,所以在01揹包兩重迴圈的前提下,在增加一重迴圈用來表示取的件數
狀態轉移方程:
dp[i][j]=max(dp[i][j],dp[i-1][j-k*w[i]]+k*v[i]);
偽**:
int w[maxn] = ;
int v[maxn] = ;
memset(dp,0,sizeof(dp));
for(int i = 1 ; i <= n ;i ++ )
}cout《對於完全揹包的滾動陣列寫法,影響dp[j]的是當前i種,而不是前i-1種,所以需要正序
int w[maxn] = ;
int v[maxn] = ;
memset(dp,0,sizeof(dp));
for (int i = 1;i <= n;i++)
} cout《多重揹包
分析:多重揹包可以成01揹包和完全揹包的結合,我們可以將相同的物品看不不同的物品,然後看作是01揹包進行求解
**:for(int i=1; i<=n; i++)//每種物品
for(int k=0; k=weight[i]; j--)//正常的01揹包**
dp[j]=max(dp[j],dp[j-weight[i]]+value[i]);
這其實和完全揹包的**一樣。。。。真神奇。。
over!
動態規劃入門 揹包問題
有n個重量和價值分別為wi,vi的物品。從這些物品中選出總重量不超過w的物品,求所有挑選方案中價值總和的最大值。在這裡,每個物品只能選一件。1 n 100 1 wi,vi 100 1 w 10000 n 4 w,v w 5 7 選擇0 1 3號物品 暴力法 複雜度o 2n include inclu...
動態規劃入門 完全揹包(硬幣兌換問題)
在乙個國家僅有1分,2分,3分硬幣,將錢n兌換成硬幣有很多種兌法。請你程式設計序計算出共有多少種兌法。input每行只有乙個正整數n,n小於32768。output對應每個輸入,輸出兌換方法數。sample input 2934 12553sample output718831 13137761 t...
動態規劃入門之揹包問題
int value maxlen 前i種物品中取若干種,在總體積不超過j的條件下取得的最大值 int weight 3500 int dvalue 3500 int main i 1時 for int j 1 j m j for int i 2 i n i for int j m j 0 j cou...