01揹包問題和徹底揹包問題

http://blog.csdn.net/kangroger/article/details/38864689ios

在hihocoder上面的題目中看到的這個問題,總結一下。先看01揹包問題。算法

01揹包問題:一個揹包總容量爲V,如今有N個物品,第i個 物品體積爲weight[i],價值爲value[i],如今往揹包裏面裝東西,怎麼裝能使揹包的內物品價值最大?數組

看到這個問題,可能會想到貪心算法,可是貪心實際上是不對的。例如最少硬幣找零問題,要用動態規劃。動態規劃思想就是解決子問題並記錄子問題的解,這樣就不用重複解決子問題了。數據結構

動態規劃先找出子問題,咱們能夠這樣考慮:在物品比較少,揹包容量比較小時怎麼解決?用一個數組f[i][j]表示,在只有i個物品,容量爲j的狀況下揹包問題的最優解,那麼當物品種類變大爲i+1時,最優解是什麼?第i+1個物品能夠選擇放進揹包或者不放進揹包(這也就是0和1),假設放進揹包(前提是放得下),那麼f[i+1][j]=f[i][j-weight[i+1]+value[i+1];若是不放進揹包,那麼f[i+1][j]=f[i][j]。app

這就得出了狀態轉移方程:oop

f[i+1][j]=max(f[i][j],f[i][j-weight[i+1]+value[i+1])。測試

能夠寫出代碼測試優化

 

[cpp]  view plain copy
 在CODE上查看代碼片派生到個人代碼片
  1. #include<iostream>  
  2. using namespace std;  
  3. #define  V 1500  
  4. unsigned int f[10][V];//全局變量,自動初始化爲0  
  5. unsigned int weight[10];  
  6. unsigned int value[10];  
  7. #define  max(x,y)   (x)>(y)?(x):(y)  
  8. int main()  
  9. {  
  10.       
  11.     int N,M;  
  12.     cin>>N;//物品個數  
  13.     cin>>M;//揹包容量  
  14.     for (int i=1;i<=N; i++)  
  15.     {  
  16.         cin>>weight[i]>>value[i];  
  17.     }  
  18.     for (int i=1; i<=N; i++)  
  19.         for (int j=1; j<=M; j++)  
  20.         {  
  21.             if (weight[i]<=j)  
  22.             {  
  23.                 f[i][j]=max(f[i-1][j],f[i-1][j-weight[i]]+value[i]);  
  24.             }  
  25.             else  
  26.                 f[i][j]=f[i-1][j];  
  27.         }  
  28.       
  29.     cout<<f[N][M]<<endl;//輸出最優解  
  30.   
  31. }  


在hihocoder上面還講到能夠進一步優化內存使用。上面計算f[i][j]能夠看出,在計算f[i][j]時只使用了f[i-1][0……j],沒有使用其餘子問題,所以在存儲子問題的解時,只存儲f[i-1]子問題的解便可。這樣能夠用兩個一維數組解決,一個存儲子問題,一個存儲正在解決的子問題。this

 

再進一步思考,計算f[i][j]時只使用了f[i-1][0……j],沒有使用f[i-1][j+1]這樣的話,咱們先計算j的循環時,讓j=M……1,只使用一個一維數組便可。spa

for i=1……N

for j=M……1

f[j]=max(f[j],f[j-weight[i]+value[i])

 

[cpp]  view plain copy
 在CODE上查看代碼片派生到個人代碼片
  1. #include<iostream>  
  2. using namespace std;  
  3. #define  V 1500  
  4. unsigned int f[V];//全局變量,自動初始化爲0  
  5. unsigned int weight[10];  
  6. unsigned int value[10];  
  7. #define  max(x,y)   (x)>(y)?(x):(y)  
  8. int main()  
  9. {  
  10.       
  11.     int N,M;  
  12.     cin>>N;//物品個數  
  13.     cin>>M;//揹包容量  
  14.     for (int i=1;i<=N; i++)  
  15.     {  
  16.         cin>>weight[i]>>value[i];  
  17.     }  
  18.     for (int i=1; i<=N; i++)  
  19.         for (int j=M; j>=1; j--)  
  20.         {  
  21.             if (weight[i]<=j)  
  22.             {  
  23.                 f[j]=max(f[j],f[j-weight[i]]+value[i]);  
  24.             }             
  25.         }  
  26.       
  27.     cout<<f[M]<<endl;//輸出最優解  
  28.   
  29. }  


在看完01揹包問題,再來看徹底揹包問題:一個揹包總容量爲V,如今有N個物品,第i個 物品體積爲weight[i],價值爲value[i],每一個物品都有無限多件,如今往揹包裏面裝東西,怎麼裝能使揹包的內物品價值最大?

 

對比一下,看到的區別是,徹底揹包問題中,物品有無限多件。往揹包裏面添加物品時,只要當前揹包沒裝滿,能夠一直添加。那麼狀態轉移方程爲:

f[i+1][j]=max(f[i][j-k*weight[i+1]+k*value[i+1]),其中0<=k<=V/weight[i+1]

使用內存爲一維數組,僞代碼

 

for i=1……N

for j=1……M

f[j]=max(f[j],f[j-weight[i]+value[i])

和01揹包問題惟一不一樣的是j是從1到M。01揹包問題是在前一個子問題(i-1種物品)的基礎上來解決當前問題(i種物品),向i-1種物品時的揹包添加第i種物品;而徹底揹包問題是在解決當前問題(i種物品),向i種物品時的揹包添加第i種物品。

代碼以下:

 

[cpp]  view plain copy
 在CODE上查看代碼片派生到個人代碼片
  1. #include<iostream>  
  2. using namespace std;  
  3. #define  V 1500  
  4. unsigned int f[V];//全局變量,自動初始化爲0  
  5. unsigned int weight[10];  
  6. unsigned int value[10];  
  7. #define  max(x,y)   (x)>(y)?(x):(y)  
  8. int main()  
  9. {  
  10.       
  11.     int N,M;  
  12.     cin>>N;//物品個數  
  13.     cin>>M;//揹包容量  
  14.     for (int i=1;i<=N; i++)  
  15.     {  
  16.         cin>>weight[i]>>value[i];  
  17.     }  
  18.     for (int i=1; i<=N; i++)  
  19.         for (int j=1; j<=M; j++)  
  20.         {  
  21.             if (weight[i]<=j)  
  22.             {  
  23.                 f[j]=max(f[j],f[j-weight[i]]+value[i]);  
  24.             }             
  25.         }  
  26.       
  27.     cout<<f[M]<<endl;//輸出最優解  
  28.   
  29. }  
相關文章
相關標籤/搜索