贪心算法在背包中的应用
来源:优易学  2011-12-10 17:13:38   【优易学:中国教育考试门户网】   资料下载   IT书店

  贪心法是一种改进了的分级处理方法。用贪心法设计算法的特点是一步一步地进行,根据某个优化测度(可能是目标函数,也可能不是目标函数),每一步上都要保证能获得局部最优解。每一步只考虑一个数据,它的选取应满足局部优化条件。若下一个数据与部分最优解连在一起不再是可行解时,就不把该数据添加到部分解中,直到把所有数据枚举完,或者不能再添加为止。这种能够得到某种度量意义下的最优解的分级处理方法称为贪心法。

  选择能产生问题最优解的最优度量标准是使用贪心法的核心问题。

  假定有n个物体和一个背包,物体i 有质量wi,价值为pi,而背包的载荷能力为M。若将物体i的一部分xi(1<=i<=n,0<=xi<=1)装入背包中,则有价值pi*xi。在约束条件(w1*x1+w2*x2+…………+wn*xn)<=M下使目标(p1*x1+p2*x2+……+pn*xn)达到极大,此处0<=xi<=1,pi>0,1<=i<=n.这个问题称为背包问题(Knapsack problem)。

  要想得到最优解,就要在效益增长和背包容量消耗两者之间寻找平衡。也就是说,总应该把那些单位效益最高的物体先放入背包。

  在实现算法的程序中,实现算法的核心程序倒没碰到很大的问题,然而实现寻找最优度量标准程序时麻烦不断!

  在寻找最优度量标准时,大致方向是用冒泡排序算法。也就是根据p[i]/w[i]的大小来对w[i]来排序。

  在直接用此算法时,可以有如下的一段代码:

  //根据效益tempArray[i]对重量w[i]排序,为进入贪心算法作准备
  1 void sort(float tempArray[], flaot w[], int n)
  2 {
  3     int i = 0, j = 0;
  4     int index = 0;
  5
  6     //用类似冒泡排序算法,根据效益p[i]/w[i]对w[i]排序
  7     for (i = 0; i < n; i++)
  8  {
  9         float swapMemory = 0;
  10        float temp;
  11
  12        temp = tempArray[i];
  13        index = i;
  14
  15        for (j = i + 1; j < n; j++)
  16        {
  17            if (temp < tempArray[j])
  18      {
  19                temp = tempArray[j];
  20                index = j;
  21      }
  22     }
  23
  24        //对w[i]排序
  25        swapMemory = w[index];
  26        w[index] = w[i];
  27        w[i] = swapMemory;
  28    }
  29
  30    return;
  31  }

  然而仔细对算法分析后可以发现,“拿来主义”在这里用不上了!

  对算法的测试用例是p[3] = {25, 24, 15};w[3] = {18, 15, 10}。得到的结果如下:

  please input the total count of object: 3
  Please input array of p :
  25 24 15
  Now please input array of w :
  18 15 10
  sortResult[i] is :
  1 -107374176.000000 1 1.600000 2  1.600000
  after arithmetic data: x[i]
  0.000000      0.333333      0.000000

  可以看到其效益为x[3] = {1.4, 1.6, 1.5},于是在M = 20的情况下,其预想中的输出结果是0,1,0.5。然而事实上是不是就这样呢?

  当程序进入此函数经过必要的变量初始化后,进入了外围循环,也就是程序的第7行。第一轮循环中,temp = tempArray[0] = 1.4,index = i = 0;程序运行到第15行,也就是进入了内层循环。

  内层循环的主要任务是从第i + 1个元素之后找到一个最大的效益并保存此时的下标。到了第24行后,就开始对w[i]进行排序。

  问题就在这里了!排序后的w[i] = {1.6, 1.6, 1.5},因此对w[i]排序后就既改变了w[i]的原有顺序,还改变了w[i]的原来值!

  据此,做出一些修改,得到了如下的一段代码:

  1 void sort(float tempArray[], int sortResult[], int n)
  2 {
  3     int i = 0, j = 0;
  4     int index = 0, k = 0;
  5
  6     for (i = 0; i < n; i++)//对映射数组赋初值0
  7  {
  8         sortResult[i] = 0;
  9  }
  10
  11    for (i = 0; i < n; i++)
  12    {
  13        float swapMemory = 0;
  14        float temp;
  15
  16        temp = tempArray[i];
  17        index = i;
  18
  19        for (j = i; j < n; j++)
  20        {
  21            if ((temp < tempArray[j]) && (sortResult[j] == 0))
  22      {
  23                temp = tempArray[j];
  24                index = j;
  25      }
  26     }
  27
  28        if (sortResult[index] == 0)
  29     {
  30            sortResult[index] = ++k;
  31     }
  32    }
  33
  34    for (i = 0; i < n; i++)
  35    {
  36        if (sortResult[i] == 0)
  37     {
  38            sortResult[i] = ++k;
  39     }
  40    }
  41
  42    return;
  43  }

  修改后最大的一个改变是没有继续沿用直接对w[i]排序,而是用w[i]的一个映射数组sortResult[i]。sortResult[i]中元素值存放的是根据效益计算得w[i]的大小顺序!这样w[i]原有的值和位置都没有改变,从而使算法得以实现!

[1] [2] 下一页

责任编辑:小草

文章搜索:
 相关文章
热点资讯
资讯快报
热门课程培训