贪心法和动态规划法的区别

来源:互联网 发布:笔记本风扇除尘软件 编辑:程序博客网 时间:2024/06/03 09:24
动态规划和贪心算法的区别
动态规划和贪心算法都是一种递推算法  均用局部最优解来推导全局最优解 

不同点: 
贪心算法: 
1.贪心算法中,作出的每步贪心决策都无法改变,因为贪心策略是由上一步的最优解推导下一步的最优解,而上一部之前的最优解则不作保留。 
2.由(1)中的介绍,可以知道贪心法正确的条件是:每一步的最优解一定包含上一步的最优解。 

动态规划算法: 
1.全局最优解中一定包含某个局部最优解,但不一定包含前一个局部最优解,因此需要记录之前的所有最优解 
2.动态规划的关键是状态转移方程,即如何由以求出的局部最优解来推导全局最优解 
3.边界条件:即最简单的,可以直接得出的局部最优解
==============================================================================
贪心算法与动态规划 
贪心法的基本思路:   
    
从问题的某一个初始解出发逐步逼近给定的目标,以尽可能快的地求得更好的解。当达到某算法中的某一步不能再继续前进时,算法停止。   
该算法存在问题:   
1.   不能保证求得的最后解是最佳的;   
2.   不能用来求最大或最小解问题;   
3.   只能求满足某些约束条件的可行解的范围。实现该算法的过程:   
从问题的某一初始解出发;
   
while   能朝给定总目标前进一步   do   
求出可行解的一个解元素;   
由所有解元素组合成问题的一个可行解 

贪心算法最经典的例子,给钱问题。   
比如中国的货币,只看元,有1元2元5元10元20、50、100   
    
如果我要16元,可以拿16个1元,8个2元,但是怎么最少呢?   
如果用贪心算,就是我每一次拿那张可能拿的最大的。   
比如16,我第一次拿20拿不起,拿10元,OK,剩下6元,再拿个5元,剩下1元   
也就是3张   10、5、1。   
    
每次拿能拿的最大的,就是贪心。   
    
但是一定注意,贪心得到的并不是最优解,也就是说用贪心不一定是拿的最少的张数   
贪心只能得到一个比较好的解,而且贪心算法很好想得到。   
再注意,为什么我们的钱可以用贪心呢?因为我们国家的钱的大小设计,正好可以使得贪心算法算出来的是最优解(一般是个国家的钱币都应该这么设计)。如果设计成别的样子情况就不同了   
比如某国的钱币分为   1元3元4元   
如果要拿6元钱   怎么拿?贪心的话   先拿4   再拿两个1     一共3张钱   
实际最优呢?   两张3元就够了   



求最优解的问题,从根本上说是一种对解空间的遍历。最直接的暴力分析容易得到,最优解的解空间通常都是以指数阶增长,因此暴力穷举都是不可行的。
最优解问题大部分都可以拆分成一个个的子问题,把解空间的遍历视作对子问题树的遍历,则以某种形式对树整个的遍历一遍就可以求出最优解,如上面的分析,这是不可行的。
贪心和动态规划本质上是对子问题树的一种修剪。两种算法要求问题都具有的一个性质就是“子问题最优性”。即,组成最优解的每一个子问题的解,对于这个子问题本身肯定也是最优的。如果以自顶向下的方向看问题树(原问题作根),则,我们每次只需要向下遍历代表最优解的子树就可以保证会得到整体的最优解。形象一点说,可以简单的用一个值(最优值)代表整个子树,而不用去求出这个子树所可能代表的所有值。
动态规划方法代表了这一类问题的一般解法。我们自底向上(从叶子向根)构造子问题的解,对每一个子树的根,求出下面每一个叶子的值,并且以其中的最优值作为自身的值,其它的值舍弃。动态规划的代价就取决于可选择的数目(树的叉数)和子问题的的数目(树的节点数,或者是树的高度?)。
贪心算法是动态规划方法的一个特例。贪心特在,可以证明,每一个子树的根的值不取决于下面叶子的值,而只取决于当前问题的状况。换句话说,不需要知道一个节点所有子树的情况,就可以求出这个节点的值。通常这个值都是对于当前的问题情况下,显而易见的“最优”情况。因此用“贪心”来描述这个算法的本质。由于贪心算法的这个特性,它对解空间树的遍历不需要自底向上,而只需要自根开始,选择最优的路,一直走到底就可以了。这样,与动态规划相比,它的代价只取决于子问题的数目,而选择数目总为1。
------------------------------

找钱问题,可以很大程度上帮助我们理解动态规划法语贪心算法的区别

二、问题

      现只有面额为 11元、5元、1元的三种人民币。

      给定一个 数目为 money 的人民币,如何用这三种面额的人民币 找开它,且用的人民币张数最少

      如:给定 10元,我们可以有以下找法:

            2张  5元面额

            1张  5元面额  + 5 张  1元面额

            10张 1元面额

      我们 选择第一种找法。只用两张人民币。

三、分析

 利用动态规划法可以找到最优解。

        利用贪心算法可以找到最优解(问题满足贪心选择性质时。该找钱问题在 11、5、1三种面额的情况下不满足该性质)

              或者找到近似 最优解(在本题设定的三种面额的情况下 便是如此)

        如果现在要找开 15元钱,则

        1. 根据动态规划法的解题思想,得到最优解为       3张  5元面额的 ,                                   总共 3张

        2. 根据贪心算法的解题思想,得到的近似最优解为 1张 11元面额的  加上  4张 1元面额的,     总共 5张

        从这就可以大略的看到 两个的区别

四、代码实现找钱问题的 动态规划法与贪心算法 两种解法,形成对比

view plaincopy to clipboardprint?
01./**********************************************************  
02. *问  题:有最小面额为 11 5 1的三种人民币,用最少的张数找钱  
03. *描  述:动态规划与贪心算法 解决问题 比较  
04. *作  者:JarvisChu  
05. **********************************************************/  
06.#include<stdio.h>   
07.#define N 4      
08.#define VALUE1 11                  //面额为 11元的人民币 (可以修改)   
09.#define VALUE2 5                   //面额为  5元的人民币 (可以修改)   
10.#define VALUE3 1                   //面额为  1元的人民币 (不要修改,不然会有找不开的情况)   
11.#define MAX_MONEY 1000             //能找开的钱的上限   
12.  
13./***************************动态规划法********************************  
14. *方法:  
15. *     int Num[MAX_MONEY];                  //Num[i]保存要找开 i 元钱,需要的最小人民币张数  
16. *     int Num_Value[N][MAX_MONEY];         //Num_Value[i][j] 表示 要找 j元钱,需要面额 VALUEi 的人民币张数  
17. *  
18. *     Num[i] = i;          0<= i <=4  
19. *     Num[i] = min(Num[i-VALUE1]+1,Num[i-VALUE2]+1,Num[i-VALUE3]+1)  
20. */  
21.  
22.//-------------------------求最小值---------------------------------   
23.int min(int a,int b,int c){   
24.    return a<b ? (a<c ? a:c):(b<c ? b:c);   
25.}   
26.//-------------------------求最优值---------------------------------   
27.int DP_Money(int money,int Num[]){   
28.                                                         //获得要找开money元钱,需要的人民币总张数              
29.    int i;   
30.    for(i=0;i<=VALUE2;i++){                               //0~4 全用 1元    
31.        Num[i]=i;   
32.    }   
33.    for(i=VALUE2;i<=money;i++){                           //从5元开始 凑钱   
34.        if(i-VALUE1 >= 0){                                //如果比 11 元大,说明多了一种用11元面额人民币的可能   
35.                                                         //从用 11元、5元、1元中 选择一个张数小的   
36.            Num[i] = min(Num[i-VALUE1]+1,Num[i-VALUE2]+1,Num[i-VALUE3]+1);   
37.        }               
38.        else{                                            //从5元、1元中 选择一个张数小的   
39.            Num[i] = (Num[i-VALUE2]+1) < (Num[i-VALUE3]+1) ? (Num[i-VALUE2]+1):(Num[i-VALUE3]+1);   
40.//          Num[i] = min(Num[i-VALUE2]+2,Num[i-VALUE2]+1,Num[i-VALUE3]+1);    
41.        }   
42.    }   
43.    return Num[money];   
44.}   
45.//-------------------------求最优解---------------------------------   
46.void BestChoice(int money,int Num[],int Num_Value[N][MAX_MONEY]){   
47.                                                           //要找 money 元钱,总人民币张数放在Num[money]中   
48.                                                           //Num[1~3][money]分别保存三种面额的张数   
49.    int i;                                                 
50.    for(i=0;i<VALUE2;i++){                            
51.        Num_Value[1][i] = 0;   
52.        Num_Value[2][i] = 0;   
53.        Num_Value[3][i] = i;   
54.    }   
55.    for(i=VALUE2;i<=money;i++){   
56.        if((i>=VALUE1) && (Num[i] == (Num[i-VALUE1]+1))){   //i 是由 i-11+11 构成  即i元是由 i-11元 加上一张面额11元的人民币构成   
57.            Num_Value[1][i] = Num_Value[1][i-VALUE1]+1;     //多一张 11元面额人民币   
58.            Num_Value[2][i] = Num_Value[2][i-VALUE1];       // 5元面额人民币 张数一样多   
59.            Num_Value[3][i] = Num_Value[3][i-VALUE1];       // 1元面额人民币 张数一样多   
60.        }   
61.        else if(Num[i] == (Num[i-VALUE2]+1)){               //i 是由 i-5+5 构成            
62.            Num_Value[1][i] = Num_Value[1][i-VALUE2];       //11元面额人民币 张数一样多   
63.            Num_Value[2][i] = Num_Value[2][i-VALUE2]+1;     //多一张 5元面额人民币   
64.            Num_Value[3][i] = Num_Value[3][i-VALUE2];       // 1元面额人民币 张数一样多   
65.        }   
66.        else if(Num[i] == (Num[i-VALUE3]+1)){               //i 是由 i-1+1 构成      
67.            Num_Value[1][i] = Num_Value[1][i-VALUE3];       //11元面额人民币 张数一样多   
68.            Num_Value[2][i] = Num_Value[2][i-VALUE3];       // 5元面额人民币 张数一样多   
69.            Num_Value[3][i] = Num_Value[3][i-VALUE3]+1;     //多一张 1元面额人民币   
70.        }   
71.        else{   
72.        }   
73.    }   
74.}   
75.  
76./***************************贪心算法********************************  
77. *方法:  
78. *     Num_Value[i]表示 面额为VALUEi 的人民币用的张数  
79. *     能用大面额的人民币,就尽量用大面额  
80. */  
81.int Greed(int money,int Num_Value[]){   
82.                                                            //要找开 money元人民币,Num_Value[1~3]保存 三种面额人民币的张数   
83.    int total=0;                                            //总张数,返回值也即是总张数。   
84.    Num_Value[1] = 0;   
85.    Num_Value[2] = 0;   
86.    Num_Value[3] = 0;   
87.    for(int i=money;i>=1;){   
88.        if(i >= VALUE1){   
89.            Num_Value[1]++;   
90.            i -= VALUE1;   
91.            total++;   
92.        }   
93.        else if(i >= VALUE2){   
94.            Num_Value[2]++;   
95.            i -= VALUE2;   
96.            total++;   
97.        }   
98.        else if(i >= VALUE3){   
99.            Num_Value[3]++;   
100.            i -= VALUE3;   
101.            total++;   
102.        }   
103.        else{   
104.        }   
105.    }   
106.    return total;   
107.}   
108.void main(){   
109.    //测试 动态规划法   
110./*  int i;  
111.    int money = 23;  
112.    int Num[MAX_MONEY];                  //Num[i]保存要找开 i 元钱,需要的最小人民币张数  
113.    int Num_Value[N][MAX_MONEY];         //Num_Value[i][j] 表示 要找 j元钱,需要面额 VALUEi 的人民币张数  
114.    printf("%d\n",DP_Money(money,Num));  
115.    printf("-------------------------------------------\n");  
116.    BestChoice(money,Num,Num_Value);  
117.    printf("-------------------------------------------\n");  
118.    for(i=0;i<=money;i++){  
119.        printf("Num[%d]=%4d, %3d, %3d, %3d\n",i,Num[i],Num_Value[1][i],Num_Value[2][i],Num_Value[3][i]);  
120.    }  
121.*/  
122.  
123.    //测试 贪心算法   
124./*  int i;  
125.    int Num_Value_Greed[4];  
126.    for(i=0;i<=40;i++){                 //从0 元到 40 元的每一个找钱方式  
127.        Greed(i,Num_Value_Greed);  
128.        printf("%d---->>> %d,%d,%d\n",i,Num_Value_Greed[1],Num_Value_Greed[2],Num_Value_Greed[3]);  
129.    }  
130.*/  
131.       
132.    //比较两个算法   
133.    int i;   
134.    int dp,grd;                         //分别保存动态规划法和贪心算法得到的人民币总张数   
135.    int money;                          //要找的钱   
136.    int Num[MAX_MONEY];                 //Num[i]保存要找i花费的银币的数目   
137.    int Num_Value[N][MAX_MONEY];        //Num_Value[i][j] 表示 要找 j 花费的 面值为 VALUEi 的硬币 的数目   
138.    int Num_Value_Greed[N];             //Num_Value_Greed[i] 表示 面值为VALUEi 的人民币 数目    
139.    money = 15;                         //可以为任意非负整型值(15 元是一个比较典型的可以区分两种算法的值)   
140.    dp = DP_Money(money,Num);          //动态规划法   
141.    BestChoice(money,Num,Num_Value);   
142.    grd = Greed(money,Num_Value_Greed); //贪心算法   
143.    printf("要找的钱 为:%d\n\n",money);   
144.    printf("  算法    张数  11元  5元  1元\n");   
145.    printf("动态规划  %-4d  %-4d  %-3d  %-3d\n",dp,Num_Value[1][money],Num_Value[2][money],Num_Value[3][money]);   
146.    printf("贪心算法  %-4d  %-4d  %-3d  %-3d\n",grd,Num_Value_Greed[1],Num_Value_Greed[2],Num_Value_Greed[3]);   
147.} 

 

本文来自CSDN博客,转载请标明出处:http://blog.csdn.net/JarvisChu/archive/2010/12/05/6056963.aspx

原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 天猫精灵方糖不支持5g怎么办 天猫精灵方糖连不上网怎么办 设置隐私相片里没什么都没有怎么办 我的手机丢了里面有隐私相片怎么办 苹果5s的id关了怎么办 用op手机快手拍视频打不开怎么办 苹果8p用流量下载不了软件怎么办 流量下载不了内存大的游戏怎么办 苹果6s开机密码忘记了怎么办 咸鱼买东西没寄买家申请退款怎么办 淘宝商品缺货又不想下架怎么办 房产代理商不给我结佣金怎么办 天猫客服遇到脾气不好的客户怎么办 美团外卖点的食品与描述不符怎么办 淘宝极速退款后买家又不想退怎么办 宝贝破损买家退回运费很高怎么办 信而富额度变0了怎么办 申请淘京猫代理时资料填错了怎么办 苹果手机能上网但微信不能用怎么办 卧室壁纸贴的太花了怎么办 贴完墙纸接头处看着是黑色的怎么办 把所有内容放在一张纸上怎么办 孩子脸上被蚊香烧了留下了疤怎么办 微信怎么修改支付密码忘了怎么办 去网鱼网咖上网没带身份证怎么办 淘宝买家号忘了账号和密码怎么办 80多岁的老人前列腺疼怎么办啊 新浪微博发二维码让我入群我怎么办 队友送的太崩了打野应该怎么办 该商品不支持在当前地区销售怎么办 此商品不支持在当前地区销售怎么办 村淘商品在淘宝没展现怎么办 qq音乐不小心充了会员怎么办 古奇的包五金磨掉色了怎么办 淘宝购物津贴买的东西退款怎么办 淘宝买的东西质量太差怎么办 咸鱼上买的东西有问题怎么办 咸鱼买到的东西有问题怎么办 天猫超市买的东西有问题怎么办 满白天的宝宝睡觉总哭怎么办 京东退货显示在售后检测要怎么办