01揹包 1維 (滾動陣列)
阿新 • • 發佈:2019-01-23
這裡先說一下二維的。
///01揹包 ///設物品有n件物品,揹包容量為w int w[]; ///代表n件物品的價值 int pw[]; ///代表n件物品各佔的容量 int f[n+50][w+50]; ///最優解二維陣列 ///f[i][j]陣列 代表存i件物品在容量為j的揹包中得到的價值 void package_01(){ for(int i=0;i<=n;i++) f[i][0]=0; for(int j=0;j<=c;j++) f[0][j]=0; ///初始化, ///若要求恰好裝滿,除這兩個初始化外,其他值全部賦值為 -0x3f3f3f3f,(這樣能夠保證最後恰好裝滿) /// for(int i=1;i<=n;i++){ ///有點列舉的感覺,列舉n件物品 for(int j=pw[i];j<=c;j++){ ///與上同理 if(f[i-1][j-pw[i]]+w[i]>f[i-1][j]) ///i-1件物品放入j-pw[i]容量的價值+w[i]的價值(即為放) 與 i-1件物品放入j容量(即為不放) 的所得價值比較 f[i][j]=f[i-1][j-pw[i]]+w[i]; else f[i][j]=f[i-1][j]; } } printf("%d\n",f[n][w]); ///f[n][w]即為最優解 }
二維的狀態轉移方程
很顯然,f[i][*] 只與 f[j-1][*] 的狀態有關 所以這裡可以有空間上的優化。
先看程式碼:
memset(dp, 0, sizeof(dp));
for(int i=0; i<n; i++){
for(int j=c; j>=pw[i]; j--){
dp[j] = max(dp[j], dp[j-pw[i]]+w[i])
}
}
對於外層的迴圈,每進行一次,dp[] 儲存的狀態都還是 i - 1 時候的dp[] ,所以在第二層迴圈使用的時候就相當於使用的是
dp[i - 1][j - pw[i]] + w[i] 與 dp[i-1][j] ..
並且,狀態轉移方程,每一次推導 f[i][j] 是通過 f[i-1][j-w[i]] 來推導的,所以一維陣列中j的掃描順序應該從大到小(c 到 0),否者前一次迴圈儲存下來的值將會被修改,從而造成錯誤。