辨析:
背包问题能用贪心算法求解,但是01背包问题不能用贪心算法求解(因为01背包问题不具备贪心选择性质----通过局部最优,达不到全局最优)
举个例子:背包容量=50; w[]={10,20,30} ,p[]={60,100,120} 用贪心选择(10+20)<50,p=160,但这并不是最优解,事实上(20+30)=50,p=100+120=220.才是问题的解。对于01背包,贪心采用自上而下,拆分子问题的方式为:{物品1,物品2,物品3}--->{物品2,物品3}----{物品3}............它无法保证最终能将背包装满,部分闲置的背包空间使每千克背包空间的价值降低了.
对于该问题,我们应该采用自下而上的动态规划来求解,拆分子问题的 方式为:{物品1}-------->{物品1,物品2}------>{物品1,物品2,物品3}.在求解时,应比较,选择该物品和不选择该物品,所导致的最终方案,然后再做出最好选择,为了更快求出问题的解。动态规划还记忆了过程中产生的许多互相重叠的子问题的答案。
贪心算法采用自上而下的方式进行子问题的求解。而动态规划则采用自下而上的方式进行子问题的求解。
算法实现:
#include<iostream>
using namespace std;
class Object {
friend void knapsack(int, float, float*, float*);
public:
int operator<=(Object a) const {
return (d >= a.d);
}
private:
int ID;
float d;
};
void knapsack(int n, float c, float v[], float w[]) {
//排序:
Object * Q = new Object[n];
for (int i = 1; i <= n; i++) {
Q[i - 1].ID = i;
Q[i - 1].d = 1.0 * v[i] / w[i];
}
//采用简单冒泡排序
for (int i = 1; i <= n; i++)
for (int j = 1; j <= n+1 - i; j++) {
if (Q[j - 1].d < Q[j].d) {
Object temp = Q[j - 1];
Q[j - 1] = Q[j];
Q[j] = temp;
}
}
// for (int i = 1; i <= n; i++) {
// cout<<"拍好序之后的: "<<endl;
// cout<<"Q[i - 1].ID: "<<Q[i - 1].ID<<endl;
// cout<<"Q[i - 1].d: "<<Q[i - 1].d<<endl;
// }
//注意:必须要新建v1和w1,不能用原来的v和w,否则对于Q[i - 1].ID这里Q[4].ID=1,
//会出现 w[4]=w[1];w[4]的值就成了2,实际我们期望的w[1]应该是5
//
float *v1 = new float[n + 1];
float *w1 = new float[n + 1];
for (int i = 1; i <= n; i++) {
v1[i] = v[Q[i - 1].ID];
w1[i] = w[Q[i - 1].ID];
cout<<"预处理后的装包顺序:"<<endl;
cout<<"v1["<<i<<"]: "<<v1[i]<<" w1["<<i<<"]: "<<w1[i]<<endl;
}
//排序结束:
int i;
float bestp=0;
float x[n + 1];
for (i = 1; i < n; i++) {
x[i] = 0;
}
//贪心算法:
for (i = 1; i < n; i++) {
if (w1[i] > c)
break;
x[i] = 1;
c -= w1[i];
}
if (i <= n)
x[i] = c / w1[i];
for (i = 1; i <= n; i++) {
if(x[i]!=0){
cout<<"选择放入的物品是:"<<Q[i - 1].ID<<endl;
cout<<"物品的"<<x[i]<<"部分被放入了背包"<<endl;
bestp+=x[i]*v[Q[i - 1].ID];
}
}
cout <<"该背包问题的最大价值是:"<<bestp << endl;
}
int main() {
float p[] = { 0, 4, 6, 3, 5, 6 };
float w[] = { 0, 5, 4, 2, 6, 2 };
float c = 10;
int n = 5;
//排好序之后的:
// int p[]={0,6,3,6,5,4};
// int w[]={0,2,2,4,6,5};
knapsack(n, c, p, w);
return 0;
}