Chinaunix首页 | 论坛 | 博客
  • 博客访问: 1435264
  • 博文数量: 241
  • 博客积分: 10
  • 博客等级: 民兵
  • 技术积分: 2253
  • 用 户 组: 普通用户
  • 注册时间: 2012-04-11 22:27
个人简介

--

文章分类

全部博文(241)

文章存档

2021年(3)

2019年(6)

2018年(1)

2017年(9)

2016年(21)

2015年(50)

2014年(125)

2013年(26)

我的朋友

分类: C/C++

2014-03-11 21:43:54

http://blog.csdn.net/jarvischu/article/details/6056963
现只有面额为 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张

        从这就可以大略的看到 两个的区别
贪心算法核心就是:将总数每次减去可以减的最大数值,直到减完。
动态规划算法核心就是:将大问题化为小问题,从1到所要计算的数字所有的最优方法,从1推出2,2推出3,以此类推。。其中有一点是每一个都是类似的问题,但是并不独立,而是和之前计算结果相关。

点击(此处)折叠或打开

  1. /**********************************************************
  2.  *问 题:有最小面额为 11 5 1的三种人民币,用最少的张数找钱
  3.  *描 述:动态规划与贪心算法 解决问题 比较
  4.  *作 者:JarvisChu
  5.  **********************************************************/
  6. #include<stdio.h>
  7. #define N 4
  8. #define VALUE1 11 //面额为 11元的人民币 (可以修改)
  9. #define VALUE2 5 //面额为 5元的人民币 (可以修改)
  10. #define VALUE3 1                 //面额为 1元的人民币 (不要修改,不然会有找不开的情况)
  11. #define MAX_MONEY 1000 //能找开的钱的上限

  12. /***************************动态规划法********************************
  13.  *方法:
  14.  *     int Num[MAX_MONEY]; //Num[i]保存要找开 i 元钱,需要的最小人民币张数
  15.  *     int Num_Value[N][MAX_MONEY]; //Num_Value[i][j] 表示 要找 j元钱,需要面额 VALUEi 的人民币张数
  16.  *
  17.  * Num[i] = i; 0<= i <=4
  18.  * Num[i] = min(Num[i-VALUE1]+1,Num[i-VALUE2]+1,Num[i-VALUE3]+1)
  19.  */

  20. //-------------------------求最小值---------------------------------
  21. int min(int a,int b,int c){
  22.     return a<b ? (a<c ? a:c):(b<c ? b:c);
  23. }
  24. //-------------------------求最优值---------------------------------
  25. int DP_Money(int money,int Num[]){
  26.                                              //获得要找开money元钱,需要的人民币总张数            
  27.     int i;
  28.     for(i=0;i<=VALUE2;i++){                                 //0~4 全用 1元
  29.         Num[i]=i;
  30.     }
  31.     for(i=VALUE2;i<=money;i++){                             //从5元开始 凑钱
  32.         if(i-VALUE1 >= 0){                                 //如果比 11 元大,说明多了一种用11元面额人民币的可能
  33.                                                          //从用 11元、5元、1元中 选择一个张数小的
  34.             Num[i] = min(Num[i-VALUE1]+1,Num[i-VALUE2]+1,Num[i-VALUE3]+1);
  35.         }
  36.         else{                                         //从5元、1元中 选择一个张数小的
  37.             Num[i] = (Num[i-VALUE2]+1) < (Num[i-VALUE3]+1) ? (Num[i-VALUE2]+1):(Num[i-VALUE3]+1);
  38. //            Num[i] = min(Num[i-VALUE2]+2,Num[i-VALUE2]+1,Num[i-VALUE3]+1);
  39.         }
  40.     }
  41.     return Num[money];
  42. }
  43. //-------------------------求最优解---------------------------------
  44. void BestChoice(int money,int Num[],int Num_Value[N][MAX_MONEY]){
  45.                                                          //要找 money 元钱,总人民币张数放在Num[money]
  46.                                                          //Num[1~3][money]分别保存三种面额的张数
  47.     int i;
  48.     for(i=0;i<VALUE2;i++){
  49.         Num_Value[1][i] = 0;
  50.         Num_Value[2][i] = 0;
  51.         Num_Value[3][i] = i;
  52.     }
  53.     for(i=VALUE2;i<=money;i++){
  54.         if((i>=VALUE1) && (Num[i] == (Num[i-VALUE1]+1))){ //i 是由 i-11+11 构成 即i元是由 i-11元 加上一张面额11元的人民币构成
  55.             Num_Value[1][i] = Num_Value[1][i-VALUE1]+1; //多一张 11元面额人民币
  56.             Num_Value[2][i] = Num_Value[2][i-VALUE1]; // 5元面额人民币 张数一样多
  57.             Num_Value[3][i] = Num_Value[3][i-VALUE1]; // 1元面额人民币 张数一样多
  58.         }
  59.         else if(Num[i] == (Num[i-VALUE2]+1)){ //i 是由 i-5+5 构成         
  60.             Num_Value[1][i] = Num_Value[1][i-VALUE2]; //11元面额人民币 张数一样多
  61.             Num_Value[2][i] = Num_Value[2][i-VALUE2]+1; //多一张 5元面额人民币
  62.             Num_Value[3][i] = Num_Value[3][i-VALUE2]; // 1元面额人民币 张数一样多
  63.         }
  64.         else if(Num[i] == (Num[i-VALUE3]+1)){ //i 是由 i-1+1 构成    
  65.             Num_Value[1][i] = Num_Value[1][i-VALUE3]; //11元面额人民币 张数一样多
  66.             Num_Value[2][i] = Num_Value[2][i-VALUE3]; // 5元面额人民币 张数一样多
  67.             Num_Value[3][i] = Num_Value[3][i-VALUE3]+1; //多一张 1元面额人民币
  68.         }
  69.         else{
  70.         }
  71.     }
  72. }

  73. /***************************贪心算法********************************
  74.  *方法:
  75.  * Num_Value[i]表示 面额为VALUEi 的人民币用的张数
  76.  * 能用大面额的人民币,就尽量用大面额
  77.  */
  78. int Greed(int money,int Num_Value[]){
  79.    //要找开 money元人民币,Num_Value[1~3]保存 三种面额人民币的张数
  80.     int total=0; //总张数,返回值也即是总张数。
  81.     Num_Value[1] = 0;
  82.     Num_Value[2] = 0;
  83.     Num_Value[3] = 0;
  84.     for(int i=money;i>=1;){
  85.         if(i >= VALUE1){
  86.             Num_Value[1]++;
  87.             i -= VALUE1;
  88.             total++;
  89.         }
  90.         else if(i >= VALUE2){
  91.             Num_Value[2]++;
  92.             i -= VALUE2;
  93.             total++;
  94.         }
  95.         else if(i >= VALUE3){
  96.             Num_Value[3]++;
  97.             i -= VALUE3;
  98.             total++;
  99.         }
  100.         else{
  101.         }
  102.     }
  103.     return total;
  104. }
  105. void main(){   
  106.     //比较两个算法
  107.     int i;
  108.     int dp,grd; //分别保存动态规划法和贪心算法得到的人民币总张数
  109.     int money; //要找的钱
  110.     int Num[MAX_MONEY]; //Num[i]保存要找i花费的银币的数目
  111.     int Num_Value[N][MAX_MONEY]; //Num_Value[i][j] 表示 要找 j 花费的 面值为 VALUEi 的硬币 的数目
  112.     int Num_Value_Greed[N]; //Num_Value_Greed[i] 表示 面值为VALUEi 的人民币 数目
  113.     money = 15; //可以为任意非负整型值(15 元是一个比较典型的可以区分两种算法的值)
  114.     dp = DP_Money(money,Num); //动态规划法
  115.     BestChoice(money,Num,Num_Value);
  116.     grd = Greed(money,Num_Value_Greed); //贪心算法
  117.     printf("要找的钱 为:%d\n",money);
  118.     printf(" 算法 张数 11元 5元 1元\n");
  119.     printf("动态规划 %-4d %-4d %-3d %-3d\n",dp,Num_Value[1][money],Num_Value[2][money],Num_Value[3][money]);
  120.     printf("贪心算法 %-4d %-4d %-3d %-3d\n",grd,Num_Value_Greed[1],Num_Value_Greed[2],Num_Value_Greed[3]);
  121. }



阅读(838) | 评论(0) | 转发(0) |
0

上一篇:哲理短句

下一篇:变参函数详解

给主人留下些什么吧!~~