贪心算法的分数背包问题的介绍与理解1(含c源代码)

来源:互联网 发布:qq三国js技能介绍 编辑:程序博客网 时间:2024/04/30 23:13

分数背包问题:

     在选择物品i装入背包时,可以选择物品i的一部分,而不一定要全部装入背包,1≤i≤n。

     类问题都具有最优子结构性质,极为相似,但背包问题可以用贪心算法求解,而0-1背包问题却不能用贪心算法求解。用贪心算法解背包问题的基本步骤是,首先计算每种物品单位重量的价值Vi/Wi,然后,依贪心选择策略,将尽可能多的单位重量价值最高的物品装入背包。若将这种物品全部装入背包后,背包内的物品总重量未超过C,则选择单位重量价值次高的物品并尽可能多地装入背包。依此策略一直地进行下去,直到背包装满为止。

算法knapsack的主要计算时间在于将各种物品依其单位重量的价值从大到小排序。因此,算法的计算时间上界为O(nlogn)。为了证明算法的正确性,还必须证明背包问题具有贪心选择性质。

贪心算法的性质:

     我们可以通过做出局部最优选择来构造全局最优解。贪心算法中,我们总是做出当时看来最佳的选择,然后求解剩下的唯一的子问题。贪心算法进行选择时可能依赖之前做出的选择,但不依赖任何将来的选择或是子问题的解。

贪心算法的设计步骤:

  1. 将最优化问题转化为这样的形式:对其做出一次选择后,只剩下一个子问题需要求解。

  2.证明做出贪心选择后,原问题总是存在最优解(贪心算法总是安全的)

  3. 证明做出贪心选择后,剩余的子问题满足性质:其最优解与贪心选择组合即可得到原问题的最优解,这样就得到了最优子结构。

例子1:  输入物品数量:3    总重量 :7    求最优的方案?

                   编号:                       1                2                  3             

           输入的重量:                    1                4                  3              

           输入的价格对应为 :        4                8                  9

例子2:   输入物品数量:3    总重量 :50   求最优的方案?

                   编号:                       1                2                 3             

           输入的重量:                    10              20               30              

           输入的价格对应为 :        60              100             140

C源代码:

#include <stdio.h>struct goodinfo            {             float p; //物品效益             float w; //物品重量             float X; //物品该放的数量             int flag; //物品编号            };//物品信息结构体 int partion1(goodinfo *arr,int p,int r);  void quicksort1(goodinfo *arr,int p,int r){if(p<r){int q;q=partion1(arr,p,r);quicksort1(arr, p, q-1);quicksort1(arr, q+1, r);} }int partion1(goodinfo *arr,int p,int r){int x,i,j;x=arr[r].p;i=p-1;for(j=p;j<r;j++){if(arr[j].p>=x)//修改大于就是从小到大序 {i=i+1;if(j!=i){goodinfo temp=arr[j];arr[j]=arr[i];arr[i]=temp;   }  } }   goodinfo temp;  temp=arr[r];  arr[r]=arr[i+1];  arr[i+1]=temp;   return i+1;} //快速排序上面的是选择最后一个点为基点; void Insertionsort(goodinfo goods[],int n) //插入排序,按pi/wi价值收益进行排序           {              int j,i;             for(j=2;j<=n;j++)             {                 goods[0]=goods[j];                 i=j-1;                              while (goods[0].p>goods[i].p)                 {                   goods[i+1]=goods[i];                   i--;                 }                 goods[i+1]=goods[0];             }            }                   //按物品效益,重量比值做升序排列 void bag(goodinfo goods[],float M,int n)            {                         float cu;             int i,j;             for(i=1;i<=n;i++)                goods[i].X=0;             cu=M;  //背包剩余容量             for(i=1;i<n;i++)             {               if(goods[i].w>cu)          //当该物品重量大与剩余容量跳出               break;               goods[i].X=1;               cu=cu-goods[i].w;           //确定背包新的剩余容量             }             if(i<=n)               goods[i].X=cu/goods[i].w;            //该物品所要放的量            /*按物品编号做降序排列*/             for(j=2;j<=n;j++)             {                 goods[0]=goods[j];                 i=j-1;                              while (goods[0].flag<goods[i].flag)                  {               goods[i+1]=goods[i];               i--;              }              goods[i+1]=goods[0];             }             printf("最优解为:\n");float sum=0;             for(i=1;i<=n;i++)             {                            printf("第%d件物品要放:",i);              printf("重量大小%f\n",goods[i].X*goods[i].w); printf("价格%f:",goods[i].p) ;               sum+=goods[i].X*goods[i].w*goods[i].p;             }             printf("最优解的效益%f\n",sum);            }            int main()            {             printf("|--------运用贪心法解分数背包问题---------|\n");             int j=1,n;    float M;             goodinfo *goods;    //定义一个指针             while(j)             {             printf("请输入物品的总数量:");             scanf("%d",&n);             goods=new struct goodinfo [n+1];//             printf("请输入背包的最大容量:");            scanf("%f",&M);            printf("\n");             int i;             for(i=1;i<=n;i++)              {   goods[i].flag=i;               printf("请输入第%d件物品的重量:",i);               scanf("%f",&goods[i].w);                                printf("请输入第%d件物品的效益:",i);                scanf("%f",&goods[i].p);               goods[i].p=goods[i].p/goods[i].w;         //得出物品的效益,重量比               printf("重量的平均价格:#%f",goods[i].p);    //很清晰的能够看到运行的过程;                  printf("\n");                            }                        //Insertionsort(goods,n); //插入的思想             quicksort1(goods,1,n); //快排的思想; //注意这里的数组是从1下标开始,如果写成0.就会出现溢出的现象;              bag(goods,M,n);             printf("press <1> to run agian\n");             printf("press <0> to exit\n");            scanf("%d",&j);             }            }


总结:

    贪心算法解决了分数背包问题,当然解决该类问题的同时,由于价格/重量的大小从大到小排序(时间复杂度O(nlgn),用到了快排和插入两种排序方式),从而取物品也是根据这个顺序来不断的抽取物品,直到达到目标的重量;其中会出现一种当有几件物品的价格/重量的大小相同时,它只取排在前面的那样物品;从而结果会不唯一,但他的最优效益唯一;这个也不能处理0-1背包问题(取物品只有取和不取,不存在只取物品的一部分),后面将会运用动态规划的方法去解决该类问题!!

0 0