還是用這題來說吧,對01背包的分析看我之前那篇就好了http://www.cnblogs.com/dominjune/p/4383762.html
這里主要是想改進一下二維數組的做法,用一維數組來實現01背包,也叫做滾動數組!
先借用某位大牛的一句話:“01背包在二維數組上操作,就是為了防止一個物品被放入多次的情況“
但其實01背包也可以用一維數組來做啦!
先看代碼:
1 #include <iostream> 2 3 using namespace std; 4 5 int w[105], val[105]; 6 int dp[1005]; 7 8 int main() 9 { 10 int t, m, res=-1; 11 cin >> t >> m; 12 for(int i=1; i<=m; i++) 13 { 14 cin >> w[i] >> val[i]; 15 } 16 for(int i=1; i<=m; i++) //物品 17 for(int j=t; j>=0; j--) //容量,逆序 18 { 19 if(j >= w[i]) 20 dp[j] = max(dp[j-w[i]]+val[i], dp[j]); 21 22 } 23 cout << dp[t] << endl; 24 return 0; 25 }
這里是把狀態只用一維數組來表示,dp[j]表示放到第j個物品(或者說是前j個物品)的時候的最大價值,少了一維,感覺好神奇...不過在我僅僅做過的題目中,好像有很多都是用滾動數組的形式...
好了,用回當年的辣個栗子:
----------------------------------------
讓我假設現在的背包的容量是C=10;
物品編號: 1 2 3
物品重量: 5 6 4
物品價值:20 10 12
---------------------------------------
直接分析dp數組:
dp:0 0 0 0 0 0 0 0 0 0
i=1:
dp[10] = max(dp[5]+20, dp[10]);
dp[9] = max(dp[4]+20, dp[9]);
dp[8] = max(dp[3]+20, dp[8]);
dp[7] = max(dp[2]+20, dp[7]);
dp[6] = max(dp[1]+20, dp[6]);
dp[5] = max(dp[0]+20, dp[5]);
dp: 0 0 0 0 20 20 20 20 20 20
---------------------------------------------
i=2:
dp[10] = max(dp[6]+4, dp[10]);
dp[9] = max(dp[3]+10, dp[9]);
dp[8] = max(dp[2]+10, dp[8]);
dp[7] = max(dp[1]+10, dp[7]);
dp[6] = max(dp[0]+10, dp[6]);
dp: 0 0 0 0 20 20 20 20 20 20 //看到了沒,選10的都被之前的20壓下去了
-------------------------------------------
i=3:
dp[10] = max(dp[6]+12, dp[10]);
dp[9] = max(dp[5]+12, dp[9]);
dp[8] = max(dp[4]+12, dp[8]);
dp[7] = max(dp[3]+12, dp[7]);
dp[6] = max(dp[2]+12, dp[6]);
dp[5] = max(dp[1]+12, dp[5]);
dp[4] = max(dp[0]+12, dp[4]);
dp: 0 0 0 12 20 20 20 20 32 32
-----------------------------------------
dp[10]就是背包容量為10的時候的最大價值,就是要求的值了,可以看到,容量大的時候的值取決於容量小的時候的值,從而不斷被正確更新,所以用滾動數組的時候,j的循環必須是從大到小逆序開始的,逆序,就防止了一個物品放入多次!!!否則...........
直接分析dp數組:
dp:0 0 0 0 0 0 0 0 0 0
i=1:
dp[5] = max(dp[0]+20, dp[5]);
dp[6] = max(dp[1]+20, dp[6]);
dp[7] = max(dp[2]+20, dp[7]);
dp[8] = max(dp[3]+20, dp[8]);
dp[9] = max(dp[4]+20, dp[9]);
dp[10] = max(dp[5]+20, dp[10]);
dp: 0 0 0 0 20 20 20 20 20 40 //看到問題了嗎!dp[10]不僅僅是由dp[5]決定了,因為dp[5]還被dp[0]更新了一次,相當於,i=1時,即只有一個物品時,這個物品拿了兩次,完全不符合01背包了,但是,這個卻是我們后面要提到的完全背包!接着看:
---------------------------------------------
i=2:
dp[6] = max(dp[0]+10, dp[6]);
dp[7] = max(dp[1]+10, dp[7]);
dp[8] = max(dp[2]+10, dp[8]);
dp[9] = max(dp[3]+10, dp[9]);
dp[10] = max(dp[4]+10, dp[10]);
dp: 0 0 0 0 20 20 20 20 20 40
-------------------------------------------
i=3:
dp[4] = max(dp[0]+12, dp[4]);
dp[5] = max(dp[1]+12, dp[5]);
dp[6] = max(dp[2]+12, dp[6]);
dp[7] = max(dp[3]+12, dp[7]);
dp[8] = max(dp[4]+12, dp[8]);
dp[9] = max(dp[5]+12, dp[9]);
dp[10] = max(dp[6]+12, dp[10]);
dp: 0 0 0 12 20 20 20 24 32 40
------------------------------------------
(其實后面不用看都知道不對了,不過我寫了就懶得刪掉......)
