贪心策略。关于贪心算法的思考,思考过程都放在代码中了。
package com.lip.datastructure;
/**
*贪心算法:装箱问题的思考
* @author Lip
*装箱问题可以是时间调问题的延伸,当一个箱子没有容积限制,那么就是时间调度问题
*在时间调度问题中:存在两个可以讨论的问题。1.平均最短时间 2.总的最短时间
*这两个问题都和装箱问题中问题如此类似。
*/
/*
* 上面是我理解的装箱问题,本来是想说背包问题的
* 背包问题的描述:有N件物品和一个容量为V的背包。第i件物品的重量是w[i],价值是v[i]。
* 求解将哪些物品装入背包可使这些物品的重量总和不超过背包容量,且价值总和最大。
*/
/*
* 贪心算法可以解决装箱问题,也可以解决背包问题,但是由贪心算法求出的解的可能不是最优解。
* 如:事实上,作为一个理性人,我们都是贪心的。当你面对一堆金银珠宝的时候,你有一个背包,你的选择肯定会是优先选择性价比最高的珠宝。
* 那么,从这个角度来说,我们可以用贪心算法来解决背包问题,即使不是问题的最优解。但是,这个解却是一个理人人的通常选择的贪心 策略。
*/
public class Pack
{
public static void main(String[] args)
{
/***********************装箱问题********************************/
int []weight={8,7,5,4,4,3,3,2,2,2,1};
int []box={12,12,12,10};
int []result=loadInBox(Type.OFFLINE, box, weight);
for(int i=0;i<box.length;i++)
{
System.out.println("第"+(i+1)+"号箱子货物:");
print(weight, result, i+1);
System.out.println();
}
// /***********0-1背包问题**************/
// int []weight={2,3,4,6,2,5,4,3,8,1};
// int []value={7,8,13,20,17,9,12,15,5,5};
// int c=20;
// int []position=loadInPack(c, value, weight);
// int sum=0;
// int sumW=0;
// for(int i=0;i<position.length;i++)
// {
// if(position[i]!=0)
// {
// sumW+=weight[position[i]-1];
// sum+=value[position[i]-1];
// System.out.println(position[i]+"->("+weight[position[i]-1]+","+value[position[i]-1]+")");
// }
// else break;
// }
// System.out.println("最大的收益为:"+sum);
// System.out.println("有多少空间没有利用:"+(c-sumW));
}
/***********************装箱问题********************************/
/**
* @param type
* @param box 箱子
* @param weight 货物重量
* @return
*/
public static int[]loadInBox(Type type,int box[],int []weight)
{
int []result=new int[weight.length];
Sort.quickSort(weight);
int sum=0;
for(int i=0;i<weight.length;i++)
sum+=weight[i];
int sum2=0;//箱子总容积
for(int i=0;i<box.length;i++)
sum2+=box[i];
if(sum>sum2)//艹,箱子不够
return null;
if(type==Type.OFFLINE)//给每个箱子都分配一个最大的货物
{
for(int i=weight.length-1,j=0;i>-1;i--)
{
int find=box.length;
while(weight[i]>box[j])//不可以装
{
j=(j+1)%box.length;
find--;
if(find==0)//箱子不够
{
System.out.println("------背包不够---------");
return null;
}
}
result[i]=j+1;
box[j]-=weight[i];
j=(j+1)%box.length;
}
}
else if(type==Type.ONLINE)//先装一个箱子
{
for(int i=0;i<box.length;i++)
{
//box[i] 箱子的当前剩余,也就是还可以装的货物
for(int j=weight.length-1;j>-1;j--)//一直装,直到装满
{
if(box[i]==0)//该箱子装满了
break;
if(result[j]==0&&weight[j]<=box[i])//该货物没有被装
{
box[i]-=weight[j];
result[j]=i+1;
}
}
}
}
return result;
}
public static void print(int []weight,int []result,int k)
{
for(int i=0;i<result.length;i++)
if(result[i]==k)
System.out.print(weight[i]+" ");
}
/**
*
* @author Lip
* 解决装箱问题有两种方式,一种是联机,一种是脱机。
* 所谓联机就是将一个箱子完全放满货物后,再开始处理下一个箱子
* 脱机就是将所有的货物都读取进来,按照从大到小的顺序将货物分配给箱子,直到各个箱子都被装满
*/
public enum Type
{
ONLINE,OFFLINE;
};
/**************************0-1背包问题(贪心算法)************************************/
/**
*
* @param c 背包容量
* @param value 每个物品的价值
* @param weight 每个物品的容积
*/
/*
* 当使用贪心算法解决背包问题时,那么考虑到贪心策略,就是要保证当前选择是最好的。
* 那么另外一个参考量“性价比”就被引用,p=value/weight
* 一直选择性价比最高的物品放入到背包中,直至背包被放满
*/
public static int[] loadInPack(int c,int[]value,int []weight)
{
double []price=new double[value.length];//性价比
int []position=new int[value.length];
int p=0;
for(int i=0;i<value.length;i++)
price[i]=(double)value[i]/weight[i];
//开始装了
while(c>0)
{
double max=-1;
int pos=-1;
for(int i=0;i<price.length;i++)//找性价比最高的,且没有被装到背包中的
{
if(price[i]!=-1&&price[i]!=0&&max<price[i])
{
max=price[i];
pos=i;
}
}
if(pos==-1)//虽然剩下空间,但是再也找不到合适的了
break;
if(c>=weight[pos])
{
c-=weight[pos];
price[pos]=-1;//已经装过
position[p]=pos+1;
p++;
}
else
{
price[pos]=0;//装不下,但是可以装比这个更小的
}
}
return position;
}
}
贪婪算法运行效果:
脱机装箱:
联机装箱:
贪心算法解决0-1背包问题:
在下篇中用动态规划法解决0-1背包问题