转:背包问题的解法
背包問題目前有兩種常規解放:遞歸方法和動態規劃法
1.動態規劃方法
轉自:http://blog.sina.com.cn/s/blog_6dcd26b301013810.html
動態規劃的基本思想:
將一個問題分解為子問題遞歸求解,且將中間結果保存以避免重復計算。通常用來求最優解,且最優解的局部也是最優的。求解過程產生多個決策序列,下一步總是依賴上一步的結果,自底向上的求解。
動態規劃算法可分解成從先到后的4個步驟:
1. 描述一個最優解的結構,尋找子問題,對問題進行劃分。
2. 定義狀態。往往將和子問題相關的各個變量的一組取值定義為一個狀態。某個狀態的值就是這個子問題的解(若有k個變量,一般用K維的數組存儲各個狀態下的解,并可根??? 據這個數組記錄打印求解過程。)。
3. 找出狀態轉移方程。一般是從一個狀態到另一個狀態時變量值改變。
4.以“自底向上”的方式計算最優解的值。
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件物品取到了最大值。
?
每一種情況也就是取兩者的最大值,來得到最后的結果的,我們很自然就聯想到了遞歸解法。
?
不斷的劃分為子問題來進行求解。
?
?
?
遞歸解法代碼:
?
C++語言:?高亮代碼由發芽網提供?
#include<iostream>using?namespace?std;
const?int?W?=?150;
const?int?number?=?5;
const?int?VALUE[]?=?{60,?20,?10,?60,?100};
const?int?WEIGHT[]?=?{20,?30,?50,?60,?80};
//function?Make(?i?{處理到第i件物品}?,?j{剩余的空間為j})?:integer;
int?Make(int?i,?int?j)
{??
int?r1?=?0;
int?r2?=?0;
int?r?=?0;
if?(i?==?-1)
{
return?0;
}
if(j?>=?WEIGHT[i])???//背包剩余空間可以放下物品?i??
{
r1?=?Make(i-1,j?-?WEIGHT[i])?+?VALUE[i];?//第i件物品放入所能得到的價值
r2?=?Make(i-1,j);?//第i件物品不放所能得到的價值??
r?=?(r1>r2)?r1:r2;
}???
return?r;
}
void?main()
{
int?maxValue?=?Make(number-1,?W);
cout<<"maxValue:?"<<maxValue<<endl;
}
?
轉載于:https://www.cnblogs.com/lscheng/p/3286419.html
總結
- 上一篇: TaskTracker获取并执行map或
- 下一篇: 服务器cpu,内存正常, 部分网站打不开