揹包問題綜合

2022-06-05 21:30:12 字數 3500 閱讀 3671

01揹包

問題:若干個物體,每個價值為c[i]重量為w[i],數量均為1,揹包最大容量為w,問怎樣取物體才能最大化收益?

解法:dp[i][j]以j為容量為放入前i個物品(按i從小到大的順序)的最大價值。有遞推關係式:dp[i][j]=max(dp[i-1][j],dp[i-1][j-w[i]]+c[i])。這裡的第一維度可以省略。

注意這裡的記憶體重量迴圈j為w到0,遞減關係(保證每個物體取一遍)(後面的不會修改前面的)

當揹包空間j少於當前物體的重量時不選該物體這一步可以省略,對後續沒有影響。

最終寫法為:

1

for(int i=1; i<=m; i++) //

物品 2

for(int j=w; j>=0; j--) //

容量 3

空間優化:

1

for(i=1;i<=m;i++)

6 }

完全揹包

問題:若干個物體,每個價值為c[i]重量為w[i],數量均為無限,揹包最大容量為w,問怎樣取物體才能最大化收益?

解法:dp[i][j]以j為容量為放入前i個物品(按i從小到大的順序)的最大價值。有遞推關係式:dp[i][j]=max(dp[i-1][j],dp[i-1][j-w[i]]+c[i])。這裡的第一維度可以省略。

注意這裡的記憶體重量迴圈j為w[i]到w,遞增關係(保證每個物體取一遍)(後面的不會修改前面的)

最終寫法為:

1

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

2for(int j=w[i]; j<=w; j++)//

注意此處,與0-1揹包不同,這裡為順序,0-1揹包為逆序

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

例題:poj2229

題意:找一些2^x(0<=x),使它們的和為n。比如,n=7: 

1) 1+1+1+1+1+1+1 

2) 1+1+1+1+1+2 

3) 1+1+1+2+2 

4) 1+1+1+4 

5) 1+2+2+2 

6) 1+2+4 

(1 <= n <= 1,000,000). 

解法:直接完全揹包即可,注意關係式更新的時候為「拿」的情況加上「不拿」的情況;注意初始化dp[0]=1

1

intn;

2int num[25];3

int dp[1000000 + 5];4

intmain() 14}

15 printf("

%d\n

", dp[n]);

16return0;

17 }

多重揹包

多重揹包裡面每個物品的數量是有限的,即k個,因此基本的求解思路是將其轉換為01揹包再求解;或者列舉k的個數。

v[i],w[i],與c[i],分別表示這種物品的體積、價值和件數。

1

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

2for (int j = m; j >= c[i]; j--)

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

4if (j - c[i] * k >= 0

)5 f[j] = max(f[j], f[j - c[i] * k] + v[i] * k);

當然直接這樣做一定會超時,其複雜度為$o(v\sum_{}^{}n[i])$。

優化方法第一種是改變分割方法(二進位制),即:將第 i 種物品分成若干件物品,其中每件物品有乙個係數,這件物品的費用和價值均是原來的費用和價值乘以這個係數。使這些係數分別為$1 , 2 , 4 ,..., 2^, n[i]-2^+1$,且k 是滿足 n[i] - 2^+1>0 的最大整數。例如,如果 n[i] 為13,就將這種物品分成係數分別為 1 , 2 , 4 , 6 的四件物品。

分成的這幾件物品的係數和為 n[i],表明不可能取多於 n[i] 件的第 i 種物品。另外這種方法也能保證對於 0 .. n[i] 間的每乙個整數,均可以用若干個係數的和表示,這個證明可以分 0.. 2^-1 和 2^...n[i] 兩段來分別討論得出。

這樣就將第i種物品分成了 o(logn[i]) 種物品,將原問題轉化為了複雜度為 o(v*∑log n[i])的01揹包問題。

1

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

10if (z > 0

) 14}15

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

16for (int j = m; j >= c[i]; j--)

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

優化方法第二種是採用優先佇列的方法,推導方法及其神奇,看不懂了,掛個鏈結

複雜度為 o(n∗v)

1

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

列舉物品種類 221

}22 }

例題:poj1742

題意:有 n 種面額的硬幣,面額個數分別為v[i]、num[i],求最多能搭配出幾種不超過 m 的金額?

解法:沒有時間、空間優化都會炸。所以採用多重揹包加上規則定義求解,定義如下:

①首先來看看樸素的方法:

bool dp[i][j] := 用前 i 種硬幣能否湊成j

遞推關係式:

dp[i][j] = (存在 k 使得 dp[i – 1][j – k * v[i]] 為真,0 <= k <= c_i 下標合法)

然後三重迴圈 i j k 遞推

這樣的話複雜度為o(m*σc_i),肯定過不去。。

②然後我們想到將問題轉化為01揹包,並利用二進位制(具體可以看揹包九講)來優化

複雜度為o(m*σlogc_i),仍然tle。。

③我們優化dp的狀態:

狀態:dp[i][j] : = 用前 i 種硬幣湊成 j 時第 i 種硬幣最多能剩餘多少個( - 1表示配不出來)

轉移:①若 $dp[i-1][j]>=0$,即前 $i-1$ 種可以配成 $j$,所以根本用不到第$i$種,所以剩餘$nun[i]$種  $dp[i][j]=nun[i]$

②若$j③其他情況,由於$a[i]$還有剩,所以$dp[i][j]$相當於在$dp[i][j-a[i]]$的基礎上多使用了乙個$a[i]$,此時  $ dp[i][j]=dp[i][j-a[i]]-1$

1

int v[106], num[106];2

intdp[maxn];

3int

n, m;

4int

main()

22int a = 1

;23 cout << ans <2526

return0;

27 }

揹包問題 01揹包問題

n個物品,總體積是v,每個物品的體積的vi,每個物品的最大價值是wi,在不超過v的體積下求最大價值 eg揹包容積為 5 物品數量為 4 物品的體積分別為 物品的價值分別為 思路定義乙個二位陣列int f new int n 1 v 1 f i j 就表示在1 i個物品中選取體積小於v的情況的最大價值...

01揹包問題 完全揹包問題 多重揹包問題

0 1 揹包問題 給定 n 種物品和乙個容量為 c 的揹包,物品 i 的重量是 wi,其價值為 vi 問 應該如何選擇裝入揹包的物品,使得裝入揹包中的物品的總價值最大?分析一波,面對每個物品,我們只有選擇拿取或者不拿兩種選擇,不能選擇裝入某物品的一部分,也不能裝入同一物品多次。解決辦法 宣告乙個 大...

01揹包問題 完全揹包問題 多重揹包問題

有n件物品和乙個容量為v 的揹包。放入第i件物品耗費的空間是ci,得到 的價值是wi。求解將哪些物品裝入揹包可使價值總和最大。這是最基礎的揹包問題,特點是 每種物品僅有一件,可以選擇放或不 放。用子問題定義狀態 即f i,v 表示前i件物品恰放入乙個容量為v的揹包可以 獲得的最大價值。則其狀態轉移方...