DP最少硬币问题:用最少数量的硬币凑够一定价值

这次同样是动态规划的问题,其核心思想与此前的viterbi算法一样:基于局部的子最优寻找全局最优,每走一步都是取决于前一步的最优解。因而,动态规划方法的计算复杂度也会大大降低。

这次的硬币问题是一个经典的动态规划问题模型:现在拥有面值为3元、6元、7元的硬币若干;问:如何用最少数量的硬币凑出18元?

分析:在考虑动态规划之前,可能我们会使用贪心算法来实现,但显然使用贪心算法7+7+3=17,并不能保证找出最优解。(贪心算法每次会选取可能的最大面值来实现硬币总数最少)并且在该问题中,最优解显然存在:6+6+6=18(最少3个硬币)。

关键点:找到状态转换方程:"d(i)=d(j)+1(j为i的前一个阶段)",并理解为何是“+1”?

现在,我们开始考虑动态规划(DP)的方法。我们设d(i)为凑够i元所需的最少硬币数目,显然d(0)=0,0元不用凑;d(1)=99999,硬币的最小面值为3元,1元显然凑不了(与之前dijkstra算法一样用99999来表示不能实现的情况);同理,d(2)=99999;当要凑够3元的时候,只需要在凑够0元的基础上再凑一个3元硬币就OK了,所以d(3)=d(3-3)+1。然后接下来:d(4)=99999;d(5)=99999;到凑6元的时候我们就发现了问题:可以用2个3元或者1个6元凑够6元。因此我们需要比较min{d(6-3)+1,d(6)=d(6-6)+1};注意,这里"d(6-3)+1"的意义在于:在凑够3元的情况下再凑3元。(即之前所说的:基于此前的状态再走一步)。但是,这里"d(6-3)+1=2>d(6-6)+1=1",最优解应是:d(6)=d(6-6)+1=1;接下来,d(7)=d(7-7)+1=1;好了,到这里,这个阶段就结束了,我们分别对d(1)~d(7)分别找到了最优解(包括无解的情况)。

好,接下去一个阶段。d(8)=99999;到凑9元了!要凑够9元,我们可以从前一个步骤的最优解解集中选一个,然后再走一步!d(9)=min{d(9-3)+1,d(9-6)+1}=2。显然,在计算d(6)时,我们就不需要再计算要选择1个6元还是2个3元了!因为前个步骤已经计算并保存了凑够6元的最优解d(6)!这就是动态规划算法的核心所在,并能降低算法复杂度的原因!


好了,不说废话了,直接上代码(c++)!

方法一:

/*递归做法*/

#include<iostream>
using namespace std;

int coins[3] = {3,6,7}; 
int d[19] ;  //存放0到18元组成的硬币数

int min(int a,int b)
{
    return (a<=b)? a:b;
}

void min_coins(int i,int num) //从i元开始凑够num元
{
    if(i == 0)
    {
        d[i] = 0;
        min_coins(1,num);
        return;
    }
    else
    {
        int MIN = 9999;
        for(int j=0;j<3;j++)
        {
            if(i>=coins[j])
            {
                MIN = min(d[i-coins[j]]+1,MIN);
            }
        }
        d[i] = MIN;

        if(i == num)return;
        else
        min_coins(i+1,num);
    }
}
int main()
{
    min_coins(0,18);        //表示要凑齐18元的硬币
    for(int i=0;i<19;i++)
    {
        cout<<"凑齐"<<i<<"元,至少需要"<<d[i]<<"枚硬币"<<endl;
    } 
    return 0; 
}

方法二:

/*循环做法*/

#include<iostream>
using namespace std;

int coins[3] = {3,6,7}; //硬币面值
int d[19]; //存放0到18元组成的硬币数

//比较大小
int min(int a, int b){
    return (a<=b) ? a:b;
}; 

//初始化
void initD(){
    for(int i=0; i<19; i++){
        d[i] = 99999;
    }
}; 

//主要功能实现
void min_coins(){
    for(int i=0; i<19; i++){
    if(i==0){
        d[0]=0;
        continue;
    }
    int MIN = 99999; //重设MIN
        for(int j=0; j<3; j++){
            if(i>=coins[j]){
                MIN = min(d[i-coins[j]]+1,MIN); //比较大小,寻找最佳
            }
            else break; //第一个不合条件就退出,优化算法
            d[i] = MIN;
        }
    }
}

void main(){
    initD();
    min_coins();
    for(int k=0; k<19; k++){
        cout<<"凑齐"<<k<<"元,至少需要"<<d[k]<<"枚硬币"<<endl; //输出结果
    }
}

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 159,015评论 4 362
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,262评论 1 292
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 108,727评论 0 243
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,986评论 0 205
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,363评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,610评论 1 219
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,871评论 2 312
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,582评论 0 198
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,297评论 1 242
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,551评论 2 246
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,053评论 1 260
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,385评论 2 253
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,035评论 3 236
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,079评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,841评论 0 195
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,648评论 2 274
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,550评论 2 270

推荐阅读更多精彩内容