背包問題之01背包


sicily 1146 采葯

還是用這題來說吧,對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

------------------------------------------ 

(其實后面不用看都知道不對了,不過我寫了就懶得刪掉......)

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM