0-1背包問題是典型的動態規划問題,看了好多博客和書面教材,一直是似懂非懂的感覺,自從看了一部教學視頻以后,感覺恍然大悟,講的確實非常通俗易懂,而且有寫代碼的過程,非常推薦!!
http://www.tudou.com/listplay/Z-bWgybEtig/XaOy3xM2klU.html
其實0-1背包問題可以抽象成一個小偷拿着一個容量有限(容量設為W)的背包去商店偷東西,每個商品都有自己的體積w和價值v,小偷的目的就是用這個容量有限的背包裝滿價值總量最大的東西。
為了討論方便,我們限定一個具體的背景,不妨設背包容量W=20,
要偷的東西的體積w和價值v分別如下:
商品名稱k | 體積w | 價值v |
0 | 2 |
3 |
1 | 3 | 4 |
2 | 4 | 5 |
3 | 5 | 8 |
4 | 9 | 10 |
當計算完B(0,2)時,按原路返回,最后得到B(4,20)。
下表是0-1背包解題過程表,可以用來記錄每一步的計算過程。
#include<stdio.h> int n,c,bestp;//物品的個數,背包的容量,最大價值 int p[10000],w[10000],x[10000],bestx[10000];//物品的價值,物品的重量,x[i]暫存物品的選中情況,物品的選中情況 void Backtrack(int i,int cp,int cw) { //cw當前包內物品重量,cp當前包內物品價值 int j; if(i>n)//回溯結束 { if(cp>bestp) { bestp=cp; for(i=0;i<=n;i++) bestx[i]=x[i]; } } else for(j=0;j<=1;j++) { x[i]=j; if(cw+x[i]*w[i]<=c) { cw+=w[i]*x[i]; cp+=p[i]*x[i]; Backtrack(i+1,cp,cw); cw-=w[i]*x[i]; cp-=p[i]*x[i]; } } } int main() { int i; bestp=0; printf("請輸入背包最大容量:\n"); scanf("%d",&c); printf("請輸入物品個數:\n"); scanf("%d",&n); printf("請依次輸入物品的重量:\n"); for(i=1;i<=n;i++) scanf("%d",&w[i]); printf("請依次輸入物品的價值:\n"); for(i=1;i<=n;i++) scanf("%d",&p[i]); Backtrack(1,0,0); printf("最大價值為:\n"); printf("%d\n",bestp); printf("被選中的物品依次是(0表示未選中,1表示選中)\n"); for(i=1;i<=n;i++) printf("%d ",bestx[i]); printf("\n"); return 0; }
程序運行結果如下:
與計算表格的右下角的值一樣,同為26,說明計算正確!