用贪心算法解决一般背包问题。
背包问题
给定N种物品和一个容量为MAX_WEIGHT的背包,物品i的重量是weight[i],其价值为price[i],背包问题是如何选择装入背包的物品,使得装入背包中物品的总价值最大?
从物品可不可以分割,背包问题可以划分为0-1背包问题和普通背包问题。
0-1背包问题适合用动态规划求解,用贪心算法获不的最优解。
普通背包问题可用贪心算法求得最优解。
对于普通背包问题的求解,至少有三种看似合理的贪心策略:
(1)选择价值最大的物品,因为这可以尽可能快地增加背包的总价值。但是,虽然每一步选择获得了背包价值的极大增长,但背包容量却可能消耗得太快,使得装入背包的物品个数减少,从而不能保证目标函数达到最大。
(2)选择重量最轻的物品,因为这可以装入尽可能多的物品,从而增加背包的总价值。但是,虽然每一步选择使背包的容量消耗的慢了,但背包的价值却没能保证迅速增长,从而不能保证目标函数达到最大。
(3)选择单位重量价值最大的物品,在背包价值增长和背包容量消耗两者之间寻找平衡。
而第三种策略则可以获得最优解,所以解决普通背包问题可以用第三种贪心策略。
下面我们用
//物品的数量
int NUMBER=6;
//背包的最大载重量
int MAX_WEIGHT=21;
//每个物品的重量
int weight[]= {5,3,2,10,4,2};
//每个物品的价值
int price[]= {11,8,15,18,13,6};
这样的数据进行测试,代码如下。
public class BagTest {
public static void main(String[] args) {
//物品的数量
int NUMBER=6;
//背包的最大载重量
int MAX_WEIGHT=21;
//每个物品的重量
int weight[]= {5,3,2,10,4,2};
//每个物品的价值
int price[]= {11,8,15,18,13,6};
//贪心算法求解普通背包问题(物品可拆解)
GreedyBag.greedybag(weight, price, MAX_WEIGHT, NUMBER);
}
}
package 贪心法解决背包问题;
public class GreedyBag {
public static void greedybag(int weight[],int price[],int MAX_WEIGHT,int NUMBER) {
int i;
double total_value=0;//可获得的最大价值
double X[]=new double[NUMBER];//存储物品存放的结果(解向量),值为0-1
//初始化解向量,java可以默认为0
for(i=0;i<X.length;i++) {
X[i]=0;
}
//surplus_capacity(剩余容量)
double surplus_capacity=MAX_WEIGHT;//背包的剩余容量
//specific(比值)定义一个数组存储单位价值
double specific[]=new double [weight.length];
for( i=0;i<specific.length;i++) {
specific[i]=(double)price[i]/weight[i];//可获得小数
}
//将重量与价值按照单位价值 降序 重新排序(冒泡排序)
for( i=0;i<specific.length-1;i++) {
for(int j=i+1;j<specific.length;j++) {
double temp=0;
if(specific[i]<specific[j]) {
//单位价值降序排序
temp=specific[i];
specific[i]=specific[j];
specific[j]=temp;
//重量重新排列
temp=weight[i];
weight[i]=weight[j];
weight[j]=(int)temp;
//价值重新排序
temp=price[i];
price[i]=price[j];
price[j]=(int)temp;
}
}
}
//将物品按单位价值降序放入背包
for(i=0;i<NUMBER;i++) {
//如果第I个物品的重量大于背包的剩余容量,则表明此物品的分割,退出循环
if(surplus_capacity<weight[i]) {
break;
}else {
//物品可以整个放入,解为1
X[i]=1;
surplus_capacity-=weight[i];//更新背包的剩余容量
}
}
//如果背包还没有被放满,则可以将此物品拆解放入(整个物品已经放不进去)
if(i<=NUMBER) {
X[i]=surplus_capacity/weight[i];//自动转成double型
}
//输出结果
for(i=0;i<NUMBER;i++) {
System.out.println("重量为:"+weight[i]+" "+"价值为:"+X[i]*price[i]+" "+"放入为:"+X[i]);
}
//计算最大的价值量
for(i=0;i<NUMBER;i++) {
total_value+=X[i]*price[i];
}
System.out.println("最大的价值量为:"+total_value);
}
}
结果如图。
如果有问题,欢迎讨论指导。