动态规划初步(硬币问题)

问题描述:现有面值为3,4,5的三种硬币(每种硬币可以重复使用),现在去商店买一个东西要X元,问如何用最少的硬币付清,而不需要对方找钱,如果无法用手中的硬币恰好凑出X则打印-1.

样例:

输入: 1   2   3  6

输出:-1 -1   1  2

分析:

有一个很直觉的思路就是先尽量用大的硬币,然后用小的硬币,举个栗子:这个题中13元可以分解为先用一个5元,再用一个5元,此时发现再用一个3元硬币就行了。哦豁,妙哇,完美解决了。

别急,举个反例看看:27元用2,5,7三种硬币,你会觉得用3个7再用3个2,一共6个硬币就行了吗。其实呢,最少的是1个7和4个5,才5个硬币。这说明贪心策略只是局部最优解而不是全局最优解,而且是暴力,不太具有普遍性。

如果用递归法的话,会发现有很多重复计算,而且空间开销大,也欠妥。

下面列出这道题的动态规划思路步骤:

一,确定状态

1、可以确定a1+a2+a3+...+ak=x元一定成立,且一定有最后的一枚面值为ak的硬币,而且除掉最后一枚硬币前面的所有硬币面值加起来一定是x-ak元

注意:不需要知道前面k-1个硬币具体是怎么样的,甚至不需要知道k和ak,但是可以确定前面的硬币拼了x-ak元

2、最优子结构:先不看最后一个ak硬币,而是要确保前面的x-ak元的拼凑方法一定是用硬币最少的!!!

二、列出状态转移方程(DP的核心)。

设f(x)=凑出X元最少用的硬币数

这道题不难推出:f(x)=min{f(x-3)+1,f(x-4)+1,f(x-5)+1};

本题的具体数据:

                     f(0)   f(1)      f(2)     f(3)     f(4)   f(5)   f(6)  f(7)   f(8)  f(9) f(10) f(11)......

需要的硬币数 0      max    max     1       1        1       2     2    . 2     2     2      3   ....

解释:

2=1*2;3=1*3;4=1*4;5=1*5;6=3*2;7=3+4;8=3+5或者4+4(但都是两枚) ;9=5+4;11=4+4+3(3枚)

三、找出初始条件

初始:b[0]=0,0元不用硬币

四、从小到大计算。

依次算出b[1],b[2],b[3]。。。其中后面的是通过前面的推出来的,不要从大往小推(b[n],b[n-1]...b[2],b[1]),至于为什么可以仔细想想。

代码写的有点杂。。。主要是确定状态转移方程中最优子结构时用了辅助变量fl和min

#include<stdio.h>
#define max 100000
int b[10000];
int main()
{
int a[3]={3,4,5};
int n,i,j;
scanf("%d",&n)//输入总价格
b[0]=0;//初始化0元不需要硬币
for(i=1;i<=n;i++)//每次循环确定一个b[i]的值,b[i]要么是max(凑不出硬币),要么是一个比较小的数
{
    int min=0;
    b[i]=max;//开始时b[i]每一个都赋值为max,默认是凑不出硬币,如果能凑出硬币则b[i]的值发生改变
    int fl=0;
    for(j=0;j<3;j++)
    {
        if(i-a[j]>=0&&!fl)
        {
        min=i-a[j]+b[i-a[j]]+1;
        fl=1;
        }
        if(i-a[j]>=0&&fl)
        {
            if(b[i-a[j]]!=max)
            {
            int sum=b[i-a[j]]+1;
            if(sum<min)
            min=sum;
            }
        }
    }
if(min>0)
    b[i]=min;
}
if(b[n]>=max)//这是不能凑出硬币的情况打印-1表示
    printf("-1");
else
    printf("%d",b[n]);

}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值