揹包問題目前有兩種常規解放:遞歸方法和動態規劃法html
1.動態規劃方法ios
轉自:http://blog.sina.com.cn/s/blog_6dcd26b301013810.htmlweb
動態規劃的基本思想:算法
將一個問題分解爲子問題遞歸求解,且將中間結果保存以免重複計算。一般用來求最優解,且最優解的局部也是最優的。求解過程產生多個決策序列,下一步老是依賴上一步的結果,自底向上的求解。數組
動態規劃算法可分解成從先到後的4個步驟:測試
1. 描述一個最優解的結構,尋找子問題,對問題進行劃分。spa
2. 定義狀態。每每將和子問題相關的各個變量的一組取值定義爲一個狀態。某個狀態的值就是這個子問題的解(如有k個變量,通常用K維的數組存儲各個狀態下的解,並可根 據這個數組記錄打印求解過程。)。code
3. 找出狀態轉移方程。通常是從一個狀態到另外一個狀態時變量值改變。orm
4.以「自底向上」的方式計算最優解的值。htm
5. 從已計算的信息中構建出最優解的路徑。(最優解是問題達到最優值的一組解)
其中步驟1~4是動態規劃求解問題的基礎,若是題目只要求最優解的值,則步驟5能夠省略。
揹包問題
01揹包: 有N件物品和一個重量爲M的揹包。(每種物品均只有一件)第i件物品的重量是w[i],價值是p[i]。求解將哪些物品裝入揹包可以使價值總和最大。
徹底揹包: 有N種物品和一個重量爲M的揹包,每種物品都有無限件可用。第i種物品的重量是w[i],價值是p[i]。求解將哪些物品裝入揹包可以使這些物品的費用總和不超過揹包重量,且價值總和最大。
多重揹包: 有N種物品和一個重量爲M的揹包。第i種物品最多有n[i]件可用,每件重量是w[i],價值是p[i]。求解將哪些物品裝入揹包可以使這些物品的費用總和不超過揹包重量,且價值總和最大。
01揹包問題:
這是最基礎的揹包問題,特色是:每種物品僅有一件,能夠選擇放或不放。
用子問題定義狀態:即c[i][v]表示前i件物品恰放入一個重量爲m的揹包能夠得到的最大價值。則其狀態轉移方程即是:
c[i][m]=max{c[i-1][m],c[i-1][m-w[i]]+p[i]}
這個方程很是重要,基本上全部跟揹包相關的問題的方程都是由它衍生出來的。因此有必要將它詳細解釋一下:「將前i件物品放入重量爲m的揹包中」這個子問題,若只考慮第i件物品的策略(放或不放),那麼就能夠轉化爲一個只牽扯前i-1件物品的問題。若是不放第i件物品,那麼問題就轉化爲「前i-1件物品放入容量爲v的揹包中」,價值爲c[i-1][m];若是放第i件物品,那麼問題就轉化爲「前i-1件物品放入剩下的重量爲m-w[i]的揹包中」,此時能得到的最大價值就是c[i-1][m-w[i]]再加上經過放入第i件物品得到的價值p[i]。
測試數據:
10,3
3,4
4,5
5,6
c[i][j]數組保存了1,2,3號物品依次選擇後的最大價值.
這個最大價值是怎麼得來的呢?從揹包容量爲0開始,1號物品先試,0,1,2,的容量都不能放.因此置0,揹包容量爲3則裏面放4.這樣,這一排揹包容量爲4,5,6,....10的時候,最佳方案都是放4.假如1號物品放入揹包.則再看2號物品.當揹包容量爲3的時候,最佳方案仍是上一排的最價方案c爲4.而揹包容量爲5的時候,則最佳方案爲本身的重量5.揹包容量爲7的時候,很顯然是5加上一個值了。加誰??很顯然是7-4=3的時候.上一排 c3的最佳方案是4.因此。總的最佳方案是5+4爲9.這樣.一排一排推下去。最右下放的數據就是最大的價值了。(注意第3排的揹包容量爲7的時候,最佳方案不是自己的6.而是上一排的9.說明這時候3號物品沒有被選.選的是1,2號物品.因此得9.)
從以上最大價值的構造過程當中能夠看出。
f(n,m)=max{f(n-1,m), f(n-1,m-w[n])+P(n,m)}這就是書本上寫的動態規劃方程.
#include<stdio.h>
int c[10][100];
int knapsack(int m,int n)
{
int i,j,w[10],p[10];
for(i=1;i<n+1;i++)
scanf("\n%d,%d",&w[i],&p[i]);
for(i=0;i<10;i++)
for(j=0;j<100;j++)
c[i][j]=0;
for(i=1;i<n+1;i++)
for(j=1;j<m+1;j++)
{
if(w[i]<=j){
if(p[i]+c[i-1][j-w[i]]>c[i-1][j])
c[i][j]=p[i]+c[i-1][j-w[i]];
else
c[i][j]=c[i-1][j];
}else
c[i][j]=c[i-1][j];
}
return(c[n][m]);
}
int main()
{
int m,n;int i,j;
printf("input the max capacity and the number of the goods:\n");
scanf("%d,%d",&m,&n);
printf("Input each one(weight and value):\n");
printf("%d",knapsack(m,n));
printf("\n");
for(i=0;i<10;i++)
for(j=0;j<15;j++)
{
printf("%d ",c[i][j]);
if(j==14)printf("\n");
}
system("pause");
}
遞歸的一個比較直觀的算法
轉自:http://hi.baidu.com/ok558/item/19779ab1922a8fd285dd793f
遞歸思想:
有N件物品和一個容量爲V的揹包。第i件物品的體積是c[i],價值是w[i]。求解將哪些物品裝入揹包可以使價值總和最大。基本思路這是最基礎的揹包問題,特色是:每種物品僅有一件,能夠選擇放或不放。用子問題定義狀態:即f[i][v]表示前i件物品恰放入一個容量爲v的揹包能夠得到的最大價值。則其狀態轉移方程即是:
解釋一下,對於第i件物品來講,最後的結果無非分爲 有 第i件商品 和 沒有第i件商品兩種狀況,
f[i-1][v]也就是有第i件商品的狀況,下面的式子天然就是沒有第i件物品取到了最大值。
每一種狀況也就是取二者的最大值,來獲得最後的結果的,咱們很天然就聯想到了遞歸解法。
不斷的劃分爲子問題來進行求解。
遞歸解法代碼: