1. 程式人生 > 其它 >01揹包 完全揹包

01揹包 完全揹包

嗨害嗨,作業來嘍

揹包問題

01揹包和完全揹包問題都是一個背景下的:我有一個容量為M的揹包,現在地上有N個物品,我跟個小偷似的眼裡只有i個物品的價值vi和重量wi,現在我要做的就是為了偷的東西更值錢拿走一些東西,使它們的價值是所有方案裡最大的

01揹包

背景如上,01揹包就是我眼前的這些東西都是孤品,只有一件,求最大價值。

那麼有些人會先想到:我可不可以等他們輸入時先計算出他們的價效比,然後再去給他們的價效比排序,得出答案呢?這就是用貪心的思想去想這道問題了,但顯然不行,因為你無法把空間利用到最大。不用貪心,我們用什麼?答案就是——動態規劃

我們可以把問題看成這樣:用一個二維陣列c[N][M]來表示N個物品放入M容量的揹包中的最大價值,那麼要計算最大價值,每個物品就只有兩種選擇方式

1.不拿,直接照抄c[i-1][j]

2.拿,拿的話我們首先要把j-w[i]把物品放進去,然後再把c[i][j-w[i]]中加上i物品的價值v[i],即得:c[i][j-w[i]]+v[i]

也就是說,我們把每個物品都拆成這樣的選最優的問題,就可以得到一行很簡單的式子:max(c[i-1][j],c[i][j-w[i]]+v[i]);這就是狀態轉移方程式

那麼有了這個我們就可以寫程式碼了,但是注意初始化c[0][j]=0,c[i][0]=0:

1 for(int i=1;i<=n;i++){
2         for(int j=1;j<=m;j++){
3             if
(j>=w[i]) c[i][j]=max(c[i-1][j],c[i][j-w[i]]+v[i]); 4 else c[i][j]=c[i-1][j]; 5 } 6 } 7 cout<<c[n][m];

注意,此時的空間複雜度為N*M

現在我們就要優化這個程式碼

max(c[i-1][j],c[i][j-w[i]]+v[i]);

我們可以看到,這個式子裡我們求第i個只需要知道i-1個物品的資料,那麼就可以把二維陣列優化成一維陣列,但是因為每個物品只能取一次,為保留前面的資料,我們就只能從後面逆推

程式碼:

1 for
(int i=1;i<=n;i++) 2 for(int j=w[i];j<=m;j++) c[j]=max(c[j],c[j-w[i]]+v[i]); 3 cout<<c[m];

完全揹包就是把逆推變成正推就歐啦

溜了溜了~