題目要求
給定n種物品和乙個揹包。物品i的質量為wi,其價值為vi,揹包的最大載重量為c。編寫乙個程式,求解如何裝載揹包裡的物品,使得裝入揹包的物品總價值最大。
題目分析
(1)這是乙個經典的問題。解決方法有很多,一般常用方法有:動態規劃,分支限界,回溯法等。在這裡先介紹一種簡單的方法–回溯法。
(2)如果把這n種物品的取捨狀態用乙個向量表示{x1
,x2 ,…,xi
,…,xn
},其中xi
只有兩種可能的取值1或0。當xi
=1是,表示將第i的物品放入揹包,當xi
=0時,表示不講第i個物品放入揹包。
(3)怎樣才能找到這樣的向量呢?一種比較直觀的方法是應用回溯法在兩棵由0-1構成的解空間樹中進行查詢。
為什麼呢?因為由概率論的知識可知,乙個n維二值向量的可能取值為2n
種,因此它的解空間相當於根結點不同的兩個n層滿二叉樹(滿二叉樹有2n
−1個葉結點,乙個葉結點代表一種結果)。所以,只要搜尋這兩棵樹,找出向量的所有可能解,再判斷這些可能的解向量是否滿足0-1揹包的條件,找出符合條件的解向量,問題就解決了。
可用剪枝操作減掉不可行的結點及以下分支。
注意:
因為要在解空間中價值總量最高的的可能解,而這樣的解不一定只有乙個 (0-1揹包問題可能有很多解),因此需要在搜尋0-1解空間樹的過程中記錄下搜尋的路徑,然後比較哪一(些)條路徑對應的裝包方案總價值最高,這一(些)條搜尋路徑對應的裝包方案就是最終的解。但是這樣做的空間複雜度較高,因為每搜尋到一條可能解路徑都要將它記錄下來,因此空間佔用量太大。
一種比較簡單的方法是分兩次回溯搜尋解空間樹,第一次搜尋計算出揹包可裝載物品的最大價值量,第二次搜尋計算出滿足這個最大價值量的全部裝包方案。這樣做雖然有些費時,但減少了空間使用。
在實際的演算法設計中,並不需要真的建立所謂的解空間樹,可以通過乙個遞迴過程模擬這個搜尋過程。
演算法描述如下:
int x[100];
//找到物品裝包的最大價值量
knap_1(int n,int flag,int c,int *price)
for(i=0;i<=1;i++)
}knap_2(int n,int flag,int c,int price)
return;
}for(i=0;i<=1;i++)
}
演算法分析:
該演算法包括兩個函式knap_ ()1和knap_2().
函式isoverload()的作用是判斷當前x中記錄的搜尋路徑對應的物品重量是否超過裝載上限c,若超載,則返回本次遞迴呼叫,相當於剪枝。引數*price為一指標型變數,是用來返回最大價值量的。返回值被knap_2()函式利用(這也是為什麼乙個是指標變數乙個是不是指標變數)
程式如下:
#include"stdio.h"
intx[100];
int val[100]=; //存放物品單價
int weight[100]=; //存放物品重量
//限重函式
int isoverload(int n,int c)
//求總價值函式
int getval(n)
//求最**值函式
knap_1(int n,int flag,int c,int
*price) //n為x陣列下標,flag為物品數量
for(i=0;ix[n]=i;
knap_1(n+1,flag,c,price);
}}//找最佳方案函式
knap_2(int n,int flag,int c,int price)
printf("--------------------\n");
getche();
return;
}for(i=0;ix[n]=i;
knap_2(n+1,flag,c,price);
}}main()
揹包問題 01揹包問題
n個物品,總體積是v,每個物品的體積的vi,每個物品的最大價值是wi,在不超過v的體積下求最大價值 eg揹包容積為 5 物品數量為 4 物品的體積分別為 物品的價值分別為 思路定義乙個二位陣列int f new int n 1 v 1 f i j 就表示在1 i個物品中選取體積小於v的情況的最大價值...
揹包問題 01揹包
有n件物品和乙個容量為v的揹包。第i件物品的重量是c i 價值是w i 求解將哪些物品裝入揹包可使價值總和最大。01揹包中的 01 就是一種物品只有1件,你可以選擇放進去揹包即1,也可以選擇不放入揹包中即0。include include using namespace std const int ...
揹包問題(01揹包)
1085 揹包問題 在n件物品取出若干件放在容量為w的揹包裡,每件物品的體積為w1,w2 wn wi為整數 與之相對應的價值為p1,p2 pn pi為整數 求揹包能夠容納的最大價值。input 第1行,2個整數,n和w中間用空格隔開。n為物品的數量,w為揹包的容量。1 n 100,1 w 10000...