数据结构之贪心算法(背包问题的思考)

  1. package com.lip.datastructure;  
  2. /** 
  3.  *贪心算法:装箱问题的思考 
  4.  * @author Lip 
  5.  *装箱问题可以是时间调问题的延伸,当一个箱子没有容积限制,那么就是时间调度问题 
  6.  *在时间调度问题中:存在两个可以讨论的问题。1.平均最短时间 2.总的最短时间 
  7.  *这两个问题都和装箱问题中问题如此类似。 
  8.  */  
  9. /* 
  10.  * 上面是我理解的装箱问题,本来是想说背包问题的 
  11.  * 背包问题的描述:有N件物品和一个容量为V的背包。第i件物品的重量是w[i],价值是v[i]。 
  12.  * 求解将哪些物品装入背包可使这些物品的重量总和不超过背包容量,且价值总和最大。 
  13.  */  
  14. /* 
  15.  * 贪心算法可以解决装箱问题,也可以解决背包问题,但是由贪心算法求出的解的可能不是最优解。 
  16.  * 如:事实上,作为一个理性人,我们都是贪心的。当你面对一堆金银珠宝的时候,你有一个背包,你的选择肯定会是优先选择性价比最高的珠宝。 
  17.  * 那么,从这个角度来说,我们可以用贪心算法来解决背包问题,即使不是问题的最优解。但是,这个解却是一个理人人的通常选择的贪心 策略。 
  18.  */  
  19. public class Pack  
  20.     {  
  21.   
  22.         public static void main(String[] args)  
  23.             {  
  24.                 /***********************装箱问题********************************/  
  25.                 int []weight={8,7,5,4,4,3,3,2,2,2,1};  
  26.                 int []box={12,12,12,10};  
  27.                 int []result=loadInBox(Type.OFFLINE, box, weight);  
  28.                   
  29.                 for(int i=0;i<box.length;i++)  
  30.                     {  
  31.                         System.out.println("第"+(i+1)+"号箱子货物:");  
  32.                         print(weight, result, i+1);  
  33.                         System.out.println();  
  34.                     }  
  35. //              /***********0-1背包问题**************/  
  36. //              int []weight={2,3,4,6,2,5,4,3,8,1};  
  37. //              int []value={7,8,13,20,17,9,12,15,5,5};  
  38. //              int c=20;  
  39. //              int []position=loadInPack(c, value, weight);  
  40. //              int sum=0;  
  41. //              int sumW=0;  
  42. //              for(int i=0;i<position.length;i++)  
  43. //                  {  
  44. //                      if(position[i]!=0)  
  45. //                          {  
  46. //                            sumW+=weight[position[i]-1];  
  47. //                            sum+=value[position[i]-1];  
  48. //                            System.out.println(position[i]+"->("+weight[position[i]-1]+","+value[position[i]-1]+")");  
  49. //                          }  
  50. //                      else break;  
  51. //                  }  
  52. //              System.out.println("最大的收益为:"+sum);  
  53. //              System.out.println("有多少空间没有利用:"+(c-sumW));  
  54.                 
  55.   
  56.             }  
  57.         /***********************装箱问题********************************/  
  58.         /** 
  59.          * @param type  
  60.          * @param box 箱子 
  61.          * @param weight 货物重量 
  62.          * @return 
  63.          */  
  64.         public static int[]loadInBox(Type type,int box[],int []weight)  
  65.         {  
  66.             int []result=new int[weight.length];  
  67.             Sort.quickSort(weight);  
  68.             int sum=0;  
  69.             for(int i=0;i<weight.length;i++)  
  70.                 sum+=weight[i];  
  71.             int sum2=0;//箱子总容积  
  72.             for(int i=0;i<box.length;i++)  
  73.                 sum2+=box[i];  
  74.             if(sum>sum2)//艹,箱子不够  
  75.                 return null;  
  76.             if(type==Type.OFFLINE)//给每个箱子都分配一个最大的货物  
  77.                 {  
  78.                     for(int i=weight.length-1,j=0;i>-1;i--)  
  79.                         {  
  80.                             int find=box.length;  
  81.                             while(weight[i]>box[j])//不可以装  
  82.                                 {  
  83.                                     j=(j+1)%box.length;  
  84.                                     find--;  
  85.                                     if(find==0)//箱子不够  
  86.                                         {  
  87.                                         System.out.println("------背包不够---------");  
  88.                                           return null;  
  89.                                         }  
  90.                                 }  
  91.                             result[i]=j+1;  
  92.                             box[j]-=weight[i];  
  93.                             j=(j+1)%box.length;  
  94.                         }  
  95.                 }  
  96.             else if(type==Type.ONLINE)//先装一个箱子  
  97.                 {  
  98.                    for(int i=0;i<box.length;i++)  
  99.                        {  
  100.                           //box[i] 箱子的当前剩余,也就是还可以装的货物  
  101.                            for(int j=weight.length-1;j>-1;j--)//一直装,直到装满  
  102.                               {  
  103.                                   if(box[i]==0)//该箱子装满了  
  104.                                       break;  
  105.                                   if(result[j]==0&&weight[j]<=box[i])//该货物没有被装  
  106.                                       {  
  107.                                           box[i]-=weight[j];  
  108.                                           result[j]=i+1;  
  109.                                       }  
  110.                               }  
  111.                        }  
  112.                 }  
  113.             return result;  
  114.         }  
  115.         public static void print(int []weight,int []result,int k)  
  116.         {  
  117.             for(int i=0;i<result.length;i++)  
  118.                 if(result[i]==k)  
  119.                     System.out.print(weight[i]+" ");  
  120.         }  
  121.         /** 
  122.          *  
  123.          * @author Lip 
  124.          * 解决装箱问题有两种方式,一种是联机,一种是脱机。 
  125.          * 所谓联机就是将一个箱子完全放满货物后,再开始处理下一个箱子 
  126.          * 脱机就是将所有的货物都读取进来,按照从大到小的顺序将货物分配给箱子,直到各个箱子都被装满 
  127.          */  
  128.         public enum Type  
  129.         {  
  130.             ONLINE,OFFLINE;  
  131.         };  
  132.         /**************************0-1背包问题(贪心算法)************************************/  
  133.         /** 
  134.          *  
  135.          * @param c 背包容量 
  136.          * @param value 每个物品的价值 
  137.          * @param weight 每个物品的容积 
  138.          */  
  139.         /* 
  140.          * 当使用贪心算法解决背包问题时,那么考虑到贪心策略,就是要保证当前选择是最好的。 
  141.          * 那么另外一个参考量“性价比”就被引用,p=value/weight 
  142.          * 一直选择性价比最高的物品放入到背包中,直至背包被放满 
  143.          */  
  144.         public static int[] loadInPack(int c,int[]value,int []weight)  
  145.         {  
  146.   
  147.             double []price=new double[value.length];//性价比  
  148.             int []position=new int[value.length];  
  149.             int p=0;  
  150.             for(int i=0;i<value.length;i++)  
  151.                 price[i]=(double)value[i]/weight[i];  
  152.             //开始装了  
  153.             while(c>0)  
  154.                 {  
  155.                     double max=-1;  
  156.                     int pos=-1;  
  157.                     for(int i=0;i<price.length;i++)//找性价比最高的,且没有被装到背包中的  
  158.                         {  
  159.                             if(price[i]!=-1&&price[i]!=0&&max<price[i])  
  160.                                 {  
  161.                                     max=price[i];  
  162.                                     pos=i;  
  163.                                 }  
  164.                         }  
  165.                     if(pos==-1)//虽然剩下空间,但是再也找不到合适的了  
  166.                         break;  
  167.                     if(c>=weight[pos])  
  168.                         {  
  169.                             c-=weight[pos];  
  170.                             price[pos]=-1;//已经装过  
  171.                             position[p]=pos+1;  
  172.                             p++;  
  173.                         }  
  174.                     else   
  175.                         {  
  176.                             price[pos]=0;//装不下,但是可以装比这个更小的  
  177.                         }  
  178.                 }  
  179.               
  180.             return position;  
  181.               
  182.         }  
  183.     }  

 

 贪婪算法运行效果:

    脱机装箱:

        

   联机装箱:

      

  贪心算法解决0-1背包问题:

     

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值