硬币找零-记忆化搜索(DP动态规划)

硬币找零

时间限制: 1000 ms  |  内存限制: 65535 KB
难度: 3
描述
在现实生活中,我们经常遇到硬币找零的问题,例如,在发工资时,财务人员就需要计 算最少的找零硬币数,以便他们能从银行拿回最少的硬币数,并保证能用这些硬币发工资。
我们应该注意到,人民币的硬币系统是 100,50,20,10,5,2,1,0.5,0.2,0.1,0.05,
0.02,0.01 元,采用这些硬币我们可以对任何一个工资数用贪心算法求出其最少硬币数。 
但不幸的是: 我们可能没有这样一种好的硬币系统, 因此用贪心算法不能求出最少的硬币数, 甚至有些金钱总数还不能用这些硬币找零。例如,如果硬币系统是 40,30,25 元,那么 37 元就不能用这些硬币找零;95 元的最少找零硬币数是 3。又如,硬币系统是 10,7,5,1 元,那么 12 元用贪心法得到的硬币数为 3,而最少硬币数是 2。 
你的任务就是:对于任意的硬币系统和一个金钱数,请你编程求出最少的找零硬币数;
如果不能用这些硬币找零,请给出一种找零方法,使剩下的钱最少。 
硬币找零-记忆化搜索(DP动态规划)_第1张图片
输入
输入数据: 
第 1 行,为 N 和 T,其中 1≤N≤50 为硬币系统中不同硬币数;1≤T≤100000 为需要用硬币找零的总数。 
第 2 行为 N 个数值不大于 65535 的正整数,它们是硬币系统中各硬币的面值。
当n,t同时为0时结束。
输出
输出数据: 
如 T 能被硬币系统中的硬币找零,请输出最少的找零硬币数。 
如 T 不能被硬币系统中的硬币找零,请输出剩下钱数最少的找零方案中的最少硬币数。
样例输入
4 12
10 7 5 1
样例输出
2
这道题目的思路与矩形嵌套有点类似,首先大家可以想到的是要想得到最少的找零硬币数肯定需要知道每一种情况,好,这样可以通过解答树将所有的情况列举出来,但是这样明显会超时,因为情况太多,而且有很多重复的子计算,所以既然要知道每一种情况,用DFS遍历,然后运用记忆化搜索的思想剪枝,将已经得到答案的最小硬币数直接返回不再重复计算
其中dp[i]代表着将i分解成硬币,最少能分成多少个。
/*
Problem: NYOJ(南阳理工OJ)
Author :2486
Memory: 1012 KB		Time: 192 MS
Language: C/C++		Result: Accepted
*/
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int maxn=100000+5;
const int INF=0x3f3f3f3f;
int n,t,a[maxn],dp[maxn],Min;
int dfs(int s) {
    if(s<0)return INF;
    if(dp[s]!=-1)return dp[s];
    Min=min(s,Min);
    int ans=INF;
    for(int i=0; i<n; i++) {
        ans=min(dfs(s-a[i])+1,ans);//得到最少硬币数
    }
    if(ans!=INF)dp[s]=ans;
    return ans;
}
int main() {
    while(~scanf("%d%d",&n,&t),n&&t) {
        for(int i=0; i<n; i++) {
            scanf("%d",&a[i]);
        }
        memset(dp,-1,sizeof(dp));
        dp[0]=0;
        Min=INF;
        dfs(t);
        if(dp[t]==-1) {//是否可以找零
            dfs(t-Min);
            printf("%d\n",dp[t-Min]);//如果不能,进行再次递归
        } else {
            printf("%d\n",dp[t]);
        }
    }
    return 0;
}


你可能感兴趣的:(硬币找零-记忆化搜索(DP动态规划))