動態規劃解背包問題/C++/Knapsack problem

來源:互聯網
上載者:User

前言

背包問題是一個經典的演算法問題,可以用動態規劃,貪進法,分支界限法等方法解決

問題描述:有n個物品,編號1,2,3,、、n,其中第 i 個物品重量為Wi 價值 Vi ,有一個容量為W的背包。

在容量允許範圍內,如何選擇物品,可以得到最大的價值。(為了簡單起見,假設物品的重量 Wi 和價值Vi 都是正數)

 

根據取物品的方式,背包問題又可以被分為三類:

0/1背包問題(0-1 knapsack problem)

這也是最常見的背包問題,對於每個物品,要麼取走要麼不取走,每個物品只能取一次。

可以用數學運算式表示為:

  • maximize   
  • subject to  
其中xi只能為1 或者0  所以稱為背包問題

有界限的背包問題(bounded knapsack problem)

對應於上文,每個物品最多可以取Gi次.也可以不取。用數學運算式描述為:

  • maximize 
  • subject to 
 

注意看xi取值範圍。其中的“界限”說的是取的次數上限

無界限背包( unbounded knapsack problem (UKP))

相應的,無界限背包說的就是每個物品取的次數無限了,也就是上文中的xi 可以為任意的正整數。

 

今天主要說的是0、1背包問題,解法是動態規劃。當然,對於另外兩種問題也會有所介紹。

問題分析:

用動態規劃解問題首先要有效找出子問題,可以通過這個子問題得推得原問題的解,通常子問題的實質是和原問題相同的,只是規模上的縮小,

也就是說子問題和原問題可以有相同的表示形式,問題可通過不斷的縮小規模(一般都會有一個界限)能找到子問題的解。

這個問題要求解的是能用背包帶走的物品的最大價值。定義 m[i,w] 為:

用第1,、2、3、、i 個物品裝入品質<=W的背包的最大價值。

m[i,w]的取值情況分析:

1)  ,背包的品質為w,裡面沒有物品,所以它的價值為0;

2)   ,背包品質為0,所以裡面沒法裝任何東西, 不論前面的 i 是多少,總價值為0;

對於任意的第 i  個物品,有兩種情況,放進背包或者不放。

不要第 i  個物品 如果 則:

3)    因為第i 個物品的重量大於背包的容量,所以不可放入。

如果. 那麼

4)  

對於第 i 個物品,有兩種可選擇方案:如果放入背包中,那麼 m[i,w]=m[i-1,w-wi]+vi 也就是 i 的前一個的最大值加上自己的價值。

如果不要第 i 個物品,那麼:m[i,w]=m[i-1,w]。也就是 i 的前一個的最大值。

因為背包問題最後要取得最大的價值,所以就選這兩種情況中價值最大的。

 

在這個問題中,定義子問題: m[i,w] 對於每個子問題,都可通過上面的分析求出。通過3),4)可以發現,每一次求取子問題,問題的規模就被縮小。

要麼在w 上減小,要麼在 i 上減小。最後問題的規模會被縮小為 m[i,0]和m[0,w].而這兩個的值都為0,只要逆向思維反推回去,就能逐步得到問題的解。

演算法描述

 

 

 

附c++代碼:

 c-free 5編譯通過

View Code

/*0、1背包問題
一條魚@部落格園
http://www.cnblogs.com/yanlingyin/
2011-12-25
*/


#include <iostream>
#include<fstream>
#include<algorithm>
#include<vector>

//儲存元素的結構
typedef struct item
{
int weight;
int values;
}item;



using namespace std;
int main()
{
int weight=10;
int itemnum=4;
//int k[10][4];


vector<vector<int> > k(11,vector<int>(5));
item items[4]={{6,30},{3,14},{4,16},{2,9}};


for(int w=0;w<=weight;w++)
{
for(int j=0;j<=itemnum;j++)
{
k[w][j]=0;
}

}

//輸出數組
for(int i=0;i<=weight;i++)
{
for(int j=0;j<=itemnum;j++)
{
cout<<k[i][j];
}
cout<<"\n";
}


for(int w=1;w<=weight;w++)
{
cout<<"測試\n";
for(int j=1;j<=itemnum;j++)
{
if(items[j-1].weight>w) //物品品質大於背包容量,捨去
{
k[w][j]=k[w][j-1];
}
else //對於兩種情況選出較大值
{
k[w][j]=max(k[w][j-1],(k[w-items[j-1].weight][j-1]+items[j-1].values));
}
cout<<"k["<<w<<"]["<<j<<"]="<<k[w][j]<<"\n";

}

}

cout<<"輸出哦了"<<k[weight][itemnum]<<"\n";

for(int i=0;i<=weight;i++)
{
for(int j=0;j<=itemnum;j++)
{
cout<<k[i][j]<<" ";
}
cout<<"\n";
}

}

 

動態規劃簡單介紹:

動態規劃通常用於最佳化問題,此類問題可能有很多可行解,每一個解有一個值,而我們希望找出一個具有最優值的解,

動態規划算法設計可分為如下步驟:

1)描述最優解的結構

2)遞迴定義最優解的值

3)按底向上的方式計算最優解的值

4)由計算出的結果構造一個最優解

動態規劃的第一步是描述最優解的結構,如果問題的一個最優解中包含了子問題的最優解,該問題具有最優解結構。當一個子問題

有最優解結構時,提示我們動態規劃適用。如本例中的m[i,w]就是一個子問題,裡麵包含了另一個子問題的最優解:

m[i-1,w],m[i-1,w-1]。解題的過程中把結果記錄在數組中,後面的解更具前面的解得出,最後找到問題的解。

 

參考資料: 

http://en.wikipedia.org/wiki/Knapsack_problem

http://www.es.ele.tue.nl/education/5MC10/Solutions/knapsack.pdf

《演算法導論》

歡迎轉載,請註明出處:http://www.cnblogs.com/yanlingyin/

一條魚@部落格園

2011-12-25

 

 

 

 


聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.