1 背包问题的描述:
已知有n种物品和一个可容纳M重量的背包,每种物品i的重量为 。假定将物品i的一部分 放入背包就会得到 的效益,这里, , 。显然,由于背包容量是M,因此,要求所有选中要装入背包的物品总重量不得超过M.。如果这n件物品的总重量不超过M,则把所有物品装入背包自然获得最大效益。现需解决的问题是,这些物品重量的和大于M,该如何装包。
2 用贪心策略求解背包问题
首先需选出最优的量度标准。不妨先取目标函数作为量度标准,即每装入一件物品就使背包获得最大可能的效益值增量。在这种量度标准下的贪心方法就是按效益值的非增次序将物品一件件放到背包中去。如果正在考虑中的物品放不进去,则可只取其一部分来装满背包。但这最后一次的方法可能不符合使背包每次获得最大效益增量的量度标准,这可以换一种能获得最大增量的物品,将它(或它的一部分)放入背包,从而使最后一次装包也符合量度标准的要求。算法如下所示。
算法1 背包问题的贪心算法
procedure GREEDY-KNAPSACK(P,W,M,X,n)
//P(1:n)和W(1:n)分别含有按P(i)/W(i)≥P(i+1)/ W (i+1)排序的n件物品的效益值和重量。M是背包的容量大笑,而X(1:n)是解向量。//
real P(1:n),W(1:n),X(1:n),M,cu;
integer i,n;
X 0 //将解向量初始化为零
cu M //cu是背包剩余容量
for i 1 to n do
if W(i)>cu then exit endif
X(i) 1
cu cu-W(i)
repeat
if i≤n then X(i) cu/W(i)
endif
end GREEDY-KNAPSACK
3 具体问题
求以下情况背包问题的最优解:n=7,M=15,( )=(10,5,15,7,6,18,3)和( )=(2,3,5,7,1,4,1)。
程序清单:
/**GreedyKnapsack.java
* 求所给背包问题的最优解
*/
package com.algorithm.knapsack;
import java.util.*;
public class GreedyKnapsack {
public void Knapsack(double P[],double W[],int M,int n)
{
int i ;
double X[] = new double[n]; //定义结果向量
for(i=0;i<X.length;i++)
X[i] = 0;
double cu = M; //cu是背包剩余重量
for(i=0;i<n;i++)
{ if(W[i]>cu)
break;
X[i] = 1;
cu = cu-W[i];
}
// System.out.println(i);
if(i<n)
X[i] = cu/W[i];
System.out.println(“问题的解为:“);
for(int k=0;k<X.length;k++)
System.out.print(X[k] + ” “);
}
public static void main(String[] args){
double P[] = {10,5,15,7,6,18,3}; //效益数组
double W[] = {2,3,5,7,1,4,1};
int M = 15,n = 7;
double PW[] = new double[P.length];
int[] index = new int[n];
for(int i= 0;i<n;i++){
PW[i] = P[i] / W[i];
index[i] =i;
}
double temp =0;
for(int i=0;i<n-1;i++)
{
for(int j=i+1;j<n;j++)
{
if(PW[i]<PW[j]) //对效益/重量数组按递增进行排序
{
temp = PW[i];
PW[i] = PW[j];
PW[j] = temp;
int x=index[i]; //交换相应的数组下标
index[i] = index[j];
index[j] = x;
}
}
}
double[] w1 = new double[n];
double[] p1 = new double[n];
for(int i=0;i<n;i++)
{
w1[i]=W[index[i]]; //将排序后的重量和价值数组分别赋给w1[]和p1[]
p1[i]=P[index[i]];
}
System.out.println(“各物品效益/重量的值为:“);
for(int i=0;i<n;i++)
System.out.print(PW[i]+” “);
System.out.println();
System.out.println (“相应的重量数组为:“+Arrays.toString(w1));
System.out.println (“相应的效益数组为:“+Arrays.toString(p1));
GreedyKnapsack gk = new GreedyKnapsack();
gk.Knapsack(P,W,M,n);
}
}