- 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背包问题: