0-1背包问题
时限:1000ms 内存限制:10000K 总时限:3000ms
描述
需对容量为c 的背包进行装载。从n 个物品中选取装入背包的物品,每件物品i 的重量为wi ,价值为pi 。对于可行的背包装载,背包中物品的总重量不能超过背包的容量,最佳装载是指所装入的物品价值最高。
输入
多个测例,每个测例的输入占三行。第一行两个整数:n(n<=10)和c,第二行n个整数分别是w1到wn,第三行n个整数分别是p1到pn。
n 和 c 都等于零标志输入结束。
n 和 c 都等于零标志输入结束。
输出
每个测例的输出占一行,输出一个整数,即最佳装载的总价值。
输入样例
1 2
1
1
2 3
2 2
3 4
0 0
1
1
2 3
2 2
3 4
0 0
输出样例
1
4
4
对于0-1背包问题来说,贪婪的策略有常用的四种。每种贪婪策略都采用多步过程来完成背包的装入。在每一步过程中利用贪婪准则选择一个物品装入背包。
一种贪婪准则为:从剩余的物品中,选出可以装入背包的价值最大的物品,利用这种规则,价值最大的物品首先被装入(假设有足够容量),然后是下一个价值最大的物品,如此继续下去。这种策略不能保证得到最优解。
第二种准则从剩下的物品中选择可装入背包的重量最小的物品,如此继续下去直到不能满足条件为止。在一般情况下不一定能得到最优解。
第三种是价值密度(价值重量比Pi/Wi)贪婪算法,这种选择准则为:从剩余物品中选择可装入包的Pi/Wi值最大的物品。这种策略也不能保证得到最优解。
第四种则为启发式贪婪算法。
下面的代码采用贪心策略一:
#include <iostream> using namespace std; typedef struct mine{ int weight; //物品的重量 int price; //物品的价值 } mine; int main() { int num,container; mine data[25]; cin>>num>>container; while(true) { if(num==0&&container==0) break; for(int i = 0;i < num; i++) cin>>data[i].weight; for(i = 0;i < num; i++) cin>>data[i].price; for(int m = 0;m < num-1; m++) //将物品按价值排序 for(int n = 0;n < num-m-1; n++) if(data[n].price<data[n+1].price) { mine temp; temp.price = data[n].price; temp.weight = data[n].weight; data[n].price = data[n+1].price; data[n].weight = data[n+1].weight; data[n+1].price = temp.price; data[n+1].weight = temp.weight; } int sumweight = 0; int sumprice = 0; for(int k = 0;k < num; k++) if(data[k].weight<=(container-sumweight)) { sumprice += data[k].price; sumweight += data[k].weight; } cout<<sumprice<<endl; cin>>num>>container; } return 0; }
并不可以保证得到最优解,例如:
输入:
10 100
4 5 6 6 7 7 8 9 11 45
7 9 11 12 13 14 15 17 21 89
输出为192
采用动态规划算法:
#include <iostream> using namespace std; int main() { int n,c,i,j; cin>>n>>c; while(n!=0||c!=0) { int *w =new int[n]; int *p =new int[n]; int **a = new int*[n+1]; for(i=0;i<=n;i++) a[i]= new int[c+1]; for(i=0;i<n;i++) cin>>w[i]; for(j=0;j<n;j++) cin>>p[j]; for(int k=0;k<c+1;k++) a[0][k] = 0; for(i=0;i<n;i++) for(j=0;j<=c;j++) { if(w[i]>j)a[i+1][j] = a[i][j]; else if(a[i][j]<a[i][j-w[i]]+p[i]) a[i+1][j] = a[i][j-w[i]]+p[i]; else a[i+1][j] = a[i][j]; } cout<<a[n][c]<<endl; cin>>n>>c; } return 0; }
对于上述同样的输入可以得到193,原因在于可以用重量为4和5的物品代替重量为11的物品,从而获得最大的价值。