有一個背包最多可裝重量8千克的物品,假設要用該背包裝如下水果,要求使背包中裝的物品的價值最大,應該裝下列哪些物品才能達到要求?
物品 | 重量 | 價值 |
蘋果 | 5千克 | 40元 |
梨 | 2千克 | 12元 |
桃子 | 1千克 | 7元 |
葡萄 | 1千克 | 8元 |
香蕉 | 6千克 | 48元 |
解題思路:首先窮舉所有組合可能,有5種物品,一共組合32-1種可能。然后排除超重的可能,在不大於8千克的前提下,再計算各種可能的總價值,最后,比較這些組合的價值,得到最大值。這種思路還是比較簡單清晰的。
二進制模擬的概念:對於每個物品,在生成的組合中有兩種可能:一是加入背包,二是排除在背包之外,這類有多種物品,每個物品有兩種可能的情況,可以使用二進制數來進行模擬。對於n個物品,就可用n位二進制模擬。位為1,表示對應物品加入背包,位為0,表示對應物品不在背包中。
int binadd(char select1[],int n) /*二進制模擬運算*/ { int i,carry=0; select1[0] += 1; for (i = 0; i < n; i++) { select1[i] += carry; //加上進位 carry = select1[i] /2;//計算進位 select1[i] %= 2; //保留0或1? if (carry==0) return 0; } return carry; }
流程:
/*-------完整代碼@映雪---------*/ /*初始化一組數據,省略用堆的繁瑣,簡化流程*/ #include <iostream> using namespace std; typedef struct { int value[5]; int weight[5]; int num; int limitw; }Goods; int bin(int s[],int n) /*二進制模擬運算*/ { int i,carry=0; s[0] += 1; for (i = 0; i < n; i++) { s[i] += carry; //加上進位 carry = s[i] /2;//計算進位 s[i] %= 2; //保留0或1? if (carry==0) return 0; } return carry; } void backpack(Goods *g,int select[])/*計算主程序*/ { int i,flag; int S[5];/*臨時狀態數組*/ double maxvalue = 0,tw,tv; for (i = 0; i < g->num; i++)//將數組清空 S[i] = 0; while(bin(S, g->num) == 0) //進行一次二進制模擬運算 { tw = 0;/*臨時重量*/ tv = 0;/*臨時價值*/ flag = 1; for (i = 0; i < g->num; i++) //根據選中狀態進行試算 { if (S[i] == 1) //若選中該物品 { tw += g->weight[i]; //累加選中物品的重量 tv += g->value[i];//累加選中物品的價值 if (tw > g->limitw) //超重 { flag = 0; break; //退出本次方案的試算 } } } if(flag && maxvalue < tv) //若方案選中物品重量未超過限制,並且本方案累加價值大於已有方案的最大價值 { maxvalue = tv; for(i = 0; i < g->num; i++) //保存方案(也是更新方案) select[i] = S[i]; } } } int main() { int sumweight,maxvalue; //用來保存階段最優價值 int select[5]; Goods g={{40,12,7,8,48},{5,2,1,1,6},5,8};/*初始化一組數據*/ backpack(&g,select); sumweight=0; maxvalue=0; printf("可將以下物品裝入背包,價值最大:\n"); for (int i = 0; i < g.num; ++i) if (select[i]) { printf("第%d號物品,重量:%d千克,價值:%d元\n", i + 1, g.weight[i], g.value[i]); sumweight+=g.weight[i]; maxvalue+=g.value[i]; } printf("\n總重量為:%d千克,總價值為:%d元\n", sumweight, maxvalue ); return 0; }