贪心算法基本思想和典型例题(转)

贪心算法

一、算法思想

贪心法的基本思路:
——从问题的某一个初始解出发逐步逼近给定的目标,以尽可能快的地求得更好的解。当达到某算法中的某一步不能再继续前进时,算法停止。
该算法存在问题:
1. 不能保证求得的最后解是最佳的;
2. 不能用来求最大或最小解问题;
3. 只能求满足某些约束条件的可行解的范围。

实现该算法的过程:
从问题的某一初始解出发;
while 能朝给定总目标前进一步 do
   求出可行解的一个解元素;
由所有解元素组合成问题的一个可行解;

二、例题分析

1、[背包问题]有一个背包,背包容量是M=150。有7个物品,物品可以分割成任意大小。
要求尽可能让装入背包中的物品总价值最大,但不能超过总容量。

物品 A  B  C D E F G
重量 35  30  60  50  40  10  25  
价值  10  40  30 50  35  40  30

分析:

目标函数: ∑pi最大
约束条件是装入的物品总重量不超过背包容量:∑wi<=M( M=150)

(1)根据贪心的策略,每次挑选价值最大的物品装入背包,得到的结果是否最优?
(2)每次挑选所占空间最小的物品装入是否能得到最优解?
(3)每次选取单位容量价值最大的物品,成为解本题的策略。

http://baike.baidu.com/view/298415.htm

实现这个算法是学习算法分析与设计这门课程的需要。

贪心算法是所接触到的第一类算法。算法从局部的最优出发,简单而快捷。对于一个问题的最

优解只能用穷举法得到时,用贪心法是寻找问题次优解的较好算法。

贪心法是一种改进了的分级处理方法。用贪心法设计算法的特点是一步一步地进行,根据某个

优化测度(可能是目标函数,也可能不是目标函数),每一步上都要保证能获得局部最优解。每一

步只考虑一个数据,它的选取应满足局部优化条件。若下一个数据与部分最优解连在一起不再是可

行解时,就不把该数据添加到部分解中,直到把所有数据枚举完,或者不能再添加为止。这种能够

得到某种度量意义下的最优解的分级处理方法称为贪心法。

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

假定有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]原有

的值和位置都没有改变,从而使算法得以实现!

至于有没有更好的实现版本,还在探索中!

#include <stdio.h>

#define MAXSIZE 100  //假设物体总数

#define M 20      //背包的载荷能力

//算法核心,贪心算法

void GREEDY(float w[], float x[], int sortResult[], int n)

{

float cu = M;

int i = 0;

int temp = 0;

for (i = 0; i < n; i++)//准备输出结果

{

x[i] = 0;

}

for (i = 0; i < n; i++)

{

temp = sortResult[i];//得到取物体的顺序

if (w[temp] > cu)

{

break;

}

x[temp] = 1;//若合适则取出

cu -= w[temp];//将容量相应的改变

}

if (i <= n)//使背包充满

{

x[temp] = cu / w[temp];

}

return;

}

void sort(float tempArray[], int sortResult[], int n)

{

int i = 0, j = 0;

int index = 0, k = 0;

for (i = 0; i < n; i++)//对映射数组赋初值0

{

sortResult[i] = 0;

}

for (i = 0; i < n; i++)

{

float temp = tempArray[i];

index = i;

//找到最大的效益并保存此时的下标

for (j = 0; j < n; j++)

{

if ((temp < tempArray[j]) && (sortResult[j] == 0))

{

temp = tempArray[j];

index = j;

}

}

//对w[i]作标记排序

if (sortResult[index] == 0)

{

sortResult[index] = ++k;

}

}

//修改效益最低的sortResult[i]标记

for (i = 0; i < n; i++)

{

if (sortResult[i] == 0)

{

sortResult[i] = ++k;

}

}

return;

}

//得到本算法的所有输入信息

void getData(float p[], float w[], int *n)

{

int i = 0;

printf("please input the total count of object: ");

scanf("%d", n);

printf("Please input array of p :\n");

for (i = 0; i < (*n); i++)

{

scanf("%f", &p[i]);

}

printf("Now please input array of w :\n");

for (i = 0; i < (*n); i++)

{

scanf("%f", &w[i]);

}

return;

}

void output(float x[], int n)

{

int i;

printf("\n\nafter arithmetic data: advise method\n");

for (i = 0; i < n; i++)

{

printf("x[%d]\t", i);

}

printf("\n");

for (i = 0; i < n; i++)

{

printf("%2.3f\t", x[i]);

}

return;

}

void main()

{

float p[MAXSIZE], w[MAXSIZE], x[MAXSIZE];

int i = 0, n = 0;

int sortResult[MAXSIZE];

getData(p, w, &n);

for (i = 0; i < n; i++)

{

x[i] = p[i] / w[i];

}

sort(x, sortResult, n);

GREEDY(w, x, sortResult, n);

output(x, n);

getch();

}

时间: 2024-10-12 04:21:09

贪心算法基本思想和典型例题(转)的相关文章

零基础学贪心算法

本文在写作过程中参考了大量资料,不能一一列举,还请见谅.贪心算法的定义:贪心算法是指在对问题求解时,总是做出在当前看来是最好的选择.也就是说,不从整体最优上加以考虑,只做出在某种意义上的局部最优解.贪心算法不是对所有问题都能得到整体最优解,关键是贪心策略的选择,选择的贪心策略必须具备无后效性,即某个状态以前的过程不会影响以后的状态,只与当前状态有关.解题的一般步骤是:1.建立数学模型来描述问题:2.把求解的问题分成若干个子问题:3.对每一子问题求解,得到子问题的局部最优解:4.把子问题的局部最优

从零开始学贪心算法

本文在写作过程中参考了大量资料,不能一一列举,还请见谅. 贪心算法的定义: 贪心算法是指在对问题求解时,总是做出在当前看来是最好的选择.也就是说,不从整体最优上加以考虑,只做出在某种意义上的局部最优解.贪心算法不是对所有问题都能得到整体最优解,关键是贪心策略的选择,选择的贪心策略必须具备无后效性,即某个状态以前的过程不会影响以后的状态,只与当前状态有关. 解题的一般步骤是: 1.建立数学模型来描述问题: 2.把求解的问题分成若干个子问题: 3.对每一子问题求解,得到子问题的局部最优解: 4.把子

五大常用算法之三贪心算法

贪心算法 贪心算法简介: 贪心算法是指:在每一步求解的步骤中,它要求"贪婪"的选择最佳操作,并希望通过一系列的最优选择,能够产生一个问题的(全局的)最优解. 贪心算法每一步必须满足一下条件: 1.可行的:即它必须满足问题的约束. 2.局部最优:他是当前步骤中所有可行选择中最佳的局部选择. 3.不可取消:即选择一旦做出,在算法的后面步骤就不可改变了. 贪心算法案例: 1.活动选择问题  这是<算法导论>上的例子,也是一个非常经典的问题.有n个需要在同一天使用同一个教室的活动a

贪心算法(Greedy Algorithm)之最小生成树 克鲁斯卡尔算法(Kruskal&amp;#39;s algorithm)

克鲁斯卡尔算法(Kruskal's algorithm)是两个经典的最小生成树算法的较为简单理解的一个.这里面充分体现了贪心算法的精髓.大致的流程能够用一个图来表示.这里的图的选择借用了Wikipedia上的那个.很清晰且直观. 首先第一步,我们有一张图,有若干点和边 例如以下图所看到的: 第一步我们要做的事情就是将全部的边的长度排序,用排序的结果作为我们选择边的根据.这里再次体现了贪心算法的思想.资源排序,对局部最优的资源进行选择. 排序完毕后,我们领先选择了边AD. 这样我们的图就变成了 第

贪心算法解硬币找零问题

假如有一种货币,它有面值为1分.2分.5分和1角的硬币,最少需要多少个硬币来找出K分钱的零钱? 按照贪心算法的思想,需要不断地使用面值最大的硬币.如果要找零的值小于最大的硬币值,则尝试第二大的硬币,依次类推. 代码如下: #include <iostream> using namespace std; #define ONE 1 #define TWO 2 #define FIVE 5 #define TEN 10 int main() { int money; int one=0,two=0

简单理解算法篇--贪心算法

贪心算法是什么意思?举个例子就很清楚了:现在你有一个能装4斤苹果的袋子,苹果有两种,一种3斤一个,一种2斤一个,怎么装才能得到最多苹果?当然我们人考虑的话当然是拿两个2斤的苹果,就刚好装满了,但是如果按贪心算法拿的话,首先就要把最重的苹果拿下(是不是很符合贪心两个字?),但并没有得到最多苹果. 贪心算法保证了局部最优,但并不能保证得到最优解. 什么时候用贪心法?满足下面两个条件 1.       具有最优子结构 2.       贪心选择性 第1点跟动态规划的条件一样,其实贪心跟动态规划一样,都

[C++]LeetCode: 77 Best Time to Buy and Sell Stock II (贪心算法)

题目: Say you have an array for which the ith element is the price of a given stock on day i. Design an algorithm to find the maximum profit. You may complete as many transactions as you like (ie, buy one and sell one share of the stock multiple times)

贪心算法——数列极差

贪心算法的思想就是用局部的最优解,达到最后全局的最优解.贪心算法使用是有限制的,一个问题能不能使用贪心来做,往往我们要对其进行必要的证明.贪心算法策略具有无后向性,也就是当前阶段的状态确定之后,不受后面阶段状态的影响. 现在我们先将一个能使用贪心算法的问题--数列极差. 问题描述:在黑板上写了N个正整数作成的一个数列,进行如下操作:每一次擦去其中的两个数a和b,然后在数列中加入一个数a*b+1,如此下去直至黑板上剩下一个数,在所有按这种操作方式最后得到的数中,最大的max,最小的为min,则该数

背包问题(贪心算法)

贪心算法(又称贪婪算法)是指,在对问题求解时,总是做出在当前看来是最好的选择.也就是说,不从整体最优上加以考虑,他所做出的是在某种意义上的局部最优解. 贪心算法还是比较好理解的一个算法,以前我也是这样认为的,感觉贪心就是每一步都做到最优解就可以了,但是后来结合问题发现自己的理解存在着一些问题.贪心算法比较经典的题目之一就是单源最短路径问题,这个问题在一些步骤上面我想了很久,有些细节想不通.这个问题以后有机会再讲.本次讲一讲背包问题. 背包问题就是有若干物品,每个物品有自己的价值和重量.背包有总重