动态规划-硬币个数最少

问题描述:小光有三种硬币,分别面值c1,c2,c3元,每种硬币的数量足够多。小光去书店买一本书耗费n元的书,如何用最少个数的硬币正好付清,不需要店主找钱,若满足,输出最少的硬币个数;若不满足,输出0。

分析:
1.假设面额为1,2,5元,n=16;则最少的个数为4,即 1+5*3=16。
2.小光付钱的过程中显然最后付的一个硬币数值有三种情况,分别是 1,2,5。假设数组 dp[i] 表示已付金额为 i 时使用的最少硬币个数,那么上述过程可以描述为:

1 dp[16] = dp[16-1]+1
2 dp[16] = dp[16-2]+1
3 dp[16] = dp[16-5]+1
anwer dp[16] = 1 + min { dp[15] , dp[14] , dp[11] }

3.当硬币面额为c1,c2,c3 ,耗费n元时 :

dp[n]=1+min { dp[n-c1] , dp[n-c2] , dp[n-c3] }

显然有:

dp[0]=0

4.注意可能存在某种情况 dp[i]求不出数值,如 面额:2 5 7 ,n=10, dp[6]就求不出来。这里的处理方法就是如果dp[i]求不出来,令dp[i]=max。初始时令 :

dp[0] = 0 , dp[i] = max i = 1,2,…,n

5.计算:

步骤 计算
初始 dp[0] = 0
step 1 dp[1]
step 2 dp[2]
step n dp[n]

6.输出:

dp[n] != max 输出 dp[n]
dp[n] == max 输出 0

完整代码展示:

#include <iostream>
using namespace std;
#define max 100000

//存储三种硬币的面额
int coin[3];
//dp[i]的意义为付i元时所需的最少硬币个数
int dp[1000];

 //求a,b中的最小值
int min(int a,int b)
{
    
    
    return a>b?b:a;
}
int dpf(int n)
{
    
    
    int i,j;
    int c1,c2,c3;
    cin>>c1>>c2>>c3;
    coin[0]=c1;
    coin[1]=c2;
    coin[2]=c3;
    //初始化
    dp[0]=0;
    for(i=1;i<=n;i++)
       dp[i]=max;
    for(i=1;i<=n;i++)
    {
    
    
        //三种金额的硬币都试,取个数最小
        for(j=0;j<=2;j++)
        {
    
    
            //只有金额i>= 硬币值 且 dp[i-硬币值]可求时才有可求dp[i]
            if(i>=coin[j]&&dp[i-coin[j]]!=max)
            {
    
    
                dp[i]=min(dp[i],1+dp[i-coin[j]]);
            }
        }
    }
    if(dp[n]!=max)
      return dp[n];
    return 0;
}
int main()
{
    
    
    int n;
    cin>>n;
    int num;
    num=dpf(n);
    cout<<num;
}

总结:
1.确定数组的含义。
2.找出数组元素的关系,确定递归关系式。
3.确定初始值。
4.写代码。

下了一周多的雨,终于停了,心情很舒坦,想学习一些基本的算法,想到之前学习C语言时,在慕课上看到的一道有关动态规划的题,就想从动态规划开始,中午看了几道相关的题如走到右下角的不同路径数,跳台阶跳法,走到右下角路径上的数字最小,硬币个数最少。挺有趣。

猜你喜欢

转载自blog.csdn.net/qq_50932477/article/details/116237881
今日推荐