背包問題(Knapsack problem)是一種組合最佳化的NP完全問題。問題可以描述為:給定一組物品,每種物品都有自己的重量和價格,在限定的總重量內,我們如何選擇,才能使得物品的總價格最高。問題的名稱來源於如何選擇最合適的物品放置於給定背包中。——引用自百度百科
背包問題是熟知的不可計算問題,這裡唯寫一下簡單的“0/1背包問題”和“連續背包問題”,至於有興趣的讀者可以再去深入瞭解一下“完全背包問題”和“多重背包問題”
0/1背包問題:
題目:有N件物品和一個容量為V的背包。第i件物品的重量是c[i],價值是w[i]。求解將哪些物品裝入背包可使這些物品的重量總和不超過背包容量,且價值總和最大。
這是最基礎的背包問題,特點是:每種物品僅有一件,可以選擇放或不放。如果每次可以拿走某一物品的任意一部分,則這一問題稱為連續背包問題
通常0/1背包問題可以採用遵歸演算法來解,連續背包問題可以採用貪心演算法來求解
遞迴演算法求解0/1背包問題的範例程式碼:
#include<stdio.h>#include<stdlib.h>//該函數首先嘗試將最後一件物品放入背包,則物品減少一件,背包可用體積相應減少,然後對目前狀態進行遞迴……//若有解則遞迴結束;若無解則拋棄最後一件物品,然後對目前狀態進行遞迴……int knap(int s, int n, int w[]) { if ( s == 0 ) return (1); else if ( s<0 || s>0 && n<1 ) return(0); else if ( knap(s - w[n-1], n - 1, w)==1 ) { //從後往前裝,如果裝滿第n個包,剩餘的重量仍然可以在剩餘的n-1包中放下,那麼就將第n個封裝滿。 printf("result: n=%d ,w[%d]=%d \n", n, n-1, w[n-1]); return (1); } else return ( knap(s, n - 1, w) );//如果裝滿第n個包後,剩餘的重量不能在剩餘的n-1包中放下,那麼就不用第n個包,考慮能不能用第n-1個包。}//s:背包的重量 n:物品的數量 w[]:每件物品的重量int main() { int* w; int s = 0, n = 0, result = 0, i = 0; printf("please input s = ");/*輸入s*/ scanf("%d", &s); printf("please input n = ");/*輸入n*/ scanf("%d", &n); w = (int*)malloc(n*sizeof(int)); printf("please input the %d numbers(weight):\n", n);/*輸入重量*/ for (i = 0; i < n; i++) scanf("%d", w+i); result = knap(s, n, w); if (result == 0) printf("no solution!\n"); return 0;}
參考資料:
1.http://zhidao.baidu.com/question/142355040.html
2.http://zhidao.baidu.com/question/189247470.html?fr=qrl&cid=866&index=1&fr2=query
3.http://www.cnblogs.com/jillzhang/archive/2007/10/06/915035.html
4.http://88myway.blog.163.com/blog/static/6926644720097124916791/
5.http://www.cppblog.com/baby-fly/archive/2009/10/24/99356.html //非遞迴演算法
6.http://zhidao.baidu.com/question/54929204.html?fr=qrl&cid=93&index=5&fr2=query //採用鏈表方法
7.http://zhidao.baidu.com/question/29685294.html?fr=qrl&cid=93&index=1&fr2=query //採用棧的方法
貪心演算法求解連續背包問題的範例程式碼:
//連續背包問題#include <iostream>#include <algorithm> #include <vector>using namespace std;#define Max 10 //初始化背包重量為10typedef struct{float price;float weight;float rate;//價格與重量的比float num;//每件物品是否能完整放下}element;bool bigger(element a,element b){return a.rate>b.rate;}void knapsack(vector<element> &test,float m){int i;for(i=0;i!=test.size();i++){if(test[i].weight>m)break;test[i].num=1;//第i件物品可以完全放到背包中m=m-test[i].weight;}if(m>0){test[i].num=m/test[i].weight;//第i件物品只能放部分i++;while(i!=test.size()){//當不是最後一件物品不能放進時test[i].num=0;i++;}}}void main(){int i,n;float m=Max;vector<element> data;element da;cout<<"input the num of goods:";cin>>n;for(i=0;i<n;i++){cout<<"input the "<<i<<" price:";cin>>da.price;cout<<"input the "<<i<<" weight:";cin>>da.weight;;da.rate=da.price/da.weight;data.push_back(da);}cout<<"build dataset:"<<endl;for(i=0;i!=data.size();i++)cout<<data[i].price<<" "<<data[i].weight<<" "<<data[i].rate<<endl;sort(data.begin(),data.end(),bigger);//將性價比最高的排在前面cout<<"after sort;"<<endl;for(i=0;i!=data.size();i++)cout<<data[i].price<<" "<<data[i].weight<<" "<<data[i].rate<<endl;cout<<"result:"<<endl;knapsack(data,m);for(i=0;i!=data.size();i++)cout<<data[i].price<<" "<<data[i].num<<endl;}
參考資料:
1.http://apps.hi.baidu.com/share/detail/16423759
2.http://wenku.baidu.com/view/ce3ebbc69ec3d5bbfd0a743e.html
3.http://wenku.baidu.com/view/afcc3e116edb6f1afe001f04.html?from=related&hasrec=1
4.http://www.cnblogs.com/gentleming/archive/2010/07/17/1779515.html