基础的DP

动态规划问题,以问题中各个子问题的解可以递推(既解互有递推关系)得来为特点,代码简介且高效。重点为找出递推关系。

通过下题展开讲解。

问题描述
:现在拥有极多种类的硬币(下列代码中假设了1 5 10 25 50五种,实际可以修改为更多种类)无限个,给定一个金额,要求输出:1.达到此金额的最小硬币数 2.最小硬币数的组成方案。

分析:
第一个问题
给定了硬币种类(面值),要求推导任意金额的最小组成硬币数。我们可以试着去列一下子问题的解

单单看面值为1的硬币时
金额:0 1 2 3 4 5 6 7 8 9 10
数目:0 1 2 3 4 5 6 7 8 9 10
可以朴素的得出min[i]=i;

如果有面值为5的硬币进行参与
金额:0 1 2 3 4 5 6 7 8 9 10
数目:0 1 2 3 4 1 2 3 4 5 2
       观察发现加入硬币5后会在只考虑硬币1得到的答案基础上有所变化,当i达到5也就金额达到5时,我们可以用一个面值为5的硬币来替代前4枚硬币+一枚面值为1的硬币的做法。简单来说就是在我们有1枚五块和五个一块时选择了前者
可以得到递推关系 dp[i]=min(dp[i],min[i-5]+1)
可以发现实际上我们添加一个新硬币进去我们就会得到这样的关系
dp[i]=min(dp[i],dp[i-新硬币数额]+1)
       好的,现在的到了这样的一个关系之后我们就可以进行打表操作,也就如下面代码的slove函数一样。

       第二个问题
       我们如何找到所谓的组成方案呢。不妨想一下,如果知道了一个金额的最小组成硬币数,那么我们也一定能知道在组成它的这些硬币中面值最大的是哪一个。
       以15为例,我们知道最大的面值为10,那么用15-10再去找,对应的就是5,5-5=0,最终方案就是10 5
       为了实现这一操作,我们需要一个数组maps来存放每一个金额对应的最小硬币数组合中的最大面值硬币。我们记金额为n,每一次都让n = n-maps[n] 那么就可以在金额不断缩小的时候(就像刚才15到5再到0)保证每次都减去了此金额对应最小硬币数组合的最大硬币面值

易得出如下代码输出对应组合:
while(n)
{
cout<<maps[n]<<" ";
n=n-maps[n];
}

       我们已经找到两个问题所对应的推导关系,这意味着DP问题已经接到达尾声,代码简洁是因为他有递归的影子,效率高是因为他不用反复运算,对已经有的数据运用效率高。

最终代码如下。

#include <iostream>
#include <algorithm>
#include <stdio.h>
#include <cstdio>
#include <string>
#include <cstring>
#include <string.h>
#include <vector>
#include <set>
#include <vector>
#include <cmath>
#include <queue>
#include <stack>
using namespace std;
int type[5]={1,5,10,25,50};
/*五种硬币*/
int dp[1000];/*假设这个最大数额是1000*/
int maps[1000]={0};
void slove()
{
    for(int i=0;i<5;i++)
    {
        for(int j=type[i];j<=1000;j++)
        {
            if(dp[j]>dp[j-type[i]]+1)
            {
                dp[j]=min(dp[j],dp[j-type[i]]+1);
                maps[j]=type[i];
            }
        }
    }
}

void show_maps(int n)
{
    while(n)
    {
        cout<<maps[n]<<" ";
        n=n-maps[n];
    }
    cout<<endl;
}

int main()
{
    int t;
   for(int i=0;i<=1000;i++)
   {
       dp[i]=INT_MAX;
   }
    dp[0]=0;
    slove();
    for(cin>>t;t;t--)
    {
        int n;
        cin>>n;
        cout<<dp[n]<<endl;
        show_maps(n);

    }
    return 0;
}

可见动态规划问题的根本就是搞出递推关系找出所有解。
拓展问题:
求出给定金额的所有硬币组成方案数(求的仅仅为一个值而不是输出所有方案)

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值