01 背包
問題描述:有N件【每件只有一個】物品和一個容量為V 的背包。第i 件物品的費用是w[i],價值是v[i],求將哪些物品裝入背包可使價值總和最大。
定義狀態:即f[i][j]表示前i件物品恰放入一個容量為j 的背包可以獲得的最大價值。
狀態轉移方程:
f[i][j]=max(f[i−1][j],f[i−1][j−w[i]]+v[i])
時間和空間復雜度均為O(VN)。時間復雜度不能再優化了,空間復雜度可以優化為O(N)
for (int i = 1; i <= n; i++) for (int j = V; j >= 0; j--) f[j] = max(f[j], f[j - w[i]] + v[i]);
注意:1:j是逆序 https://blog.csdn.net/yandaoqiusheng/article/details/84929357
2 w[i]和v[i]中是i
可以進行優化的原因:每次寫入數據都是根據上一行的結果寫入的,數組一維就夠用了
其中的f[j]=max(f[j],f[j−w[i]]) 一句相當於轉移方程f[i][j]=max(f[i−1][j],f[i−1][j−w[i]]) ,因為現在的f[j−w[i]]就相當於原來的f[i−1][j−w[i]]。
注意上述代碼中利用了滾動數組原理
完全背包:
問題描述:有N種【每種有無數個】物品和一個容量為V的背包,每種物品都有無限件可用。第i種物品的費用是w[i],價值是v[i]。求解將哪些物品裝入背包可使這些物品的費用總和不超過背包容量,且價值總和最大。狀態轉移方程:
f[i][j]=max(f[i−1][j−k∗w[i]]+k∗v[i])∣0<=k∗w[i]<=j
注意:f[i−1],不是f[i]
狀態轉移方程含義:若k=0,f[i−1][j]即j費用全部取前i-1種物品;若k=1,f[i−1[j−w[i]]+v[i],即j-w[i]費用取前i-1種物品,w[i]費用取第i種物品。。。。。
優化為O(VN):
for (int i = 1; i <= n; i++) for (int j = w[i]; j <= V; j++)
f(i,j)=
f(i-1,j),如果不取第i件物品
f(i,j-w(i))+v(i),如果取第i件物品
解釋一下,為什么一位數組中,不用寫k循環。[其他博客中均沒有詳細解釋這一點,我這里用自己的話來理解下】
假設不考慮【f(i-1,j),如果不取第i件物品】這種情況
j=w(i)時,表示此次取一件i物品,f(i,0)+v(i)表示加上一件第i件物品的值,得到f(i,w(i))
j=2*w(i)時,由於滾動數組,f(i,w(i))已經是上一次的f(i,w(i)),已經加了一次w[i],所以這次只需再加一件w[i]即可。
...............
多次循環后,其實就等同於二維數組中的k循環了
寫成代碼:
for (int i = 1; i <= n; i++) for (int j = w[i]; j <= V; j++) f[j] = max(f[j], f[j - w[i]] + v[i]);
f[j]表示放入N種物品獲得的最大價值
注意:正序
參考文獻1
背包9講:https://blog.csdn.net/yandaoqiusheng/article/details/84782655
完全背包優化:https://blog.csdn.net/wumuzi520/article/details/7014830