版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/Tianweidadada/article/details/82990233
题意:给定金额n,有50,25,10,5,1这五种面值的钱,问共有多少种不同的找法(假设最少存在一种找法)。
这题我想了很久,都没有找到合适的状态转移方程,最后看了别人写的,又体会了半天,才算明白。
分析:
这题,写不对原因在于,很容易就重复计算了。例如 11 中的 (11111,5,111111)与(11111,111111,5)视为一种。
那么怎么避免重复计算呢。
首先从小的到大枚举面额(这个必须在外面循环)
比如 枚举 dp[0] = 1,dp[1] = 1,dp[2] = 1,d[3] = 1,dp[4] = 1
当枚举到dp[5]的 时候 第一遍 的结果是 dp[5] += dp[5-1] 此时 dp[5] = dp[4] = 1(实际上dp[5] = 2),下一个循环枚举到
dp[5]的时候,dp[5] += dp[5-5] = 2。这样单独看某个值,最后都会遍历到每一个面值,也就是最终会满足dp方程
这样 第一遍 dp[6] += dp[6-1] =>dp[6] = dp[5] = 1, 第二遍 dp[6] += dp[6-5] =>dp[6] = 1 + dp[1] 不会重复。
code:
#include<iostream>
#include<cmath>
#include<cstring>
#include<cstdio>
#include<vector>
#include<map>
#include<algorithm>
#include<string>
using namespace std;
const int N = 10000;
int cost[10] = {1,5,10,25,50};
int dp[N];
int main()
{
// dp[i] 表示 金钱 i 可以有多少种表示方法
int n;
memset(dp,0,sizeof(dp));
dp[0] = 1;
for(int i = 0; i < 5; ++i){ // 两层 循环不可互换 否则 重复
for(int j = cost[i]; j < N; ++j){
dp[j] += dp[j-cost[i]];
}
}
while(scanf("%d",&n) != EOF){
printf("%d\n",dp[n]);
}
return 0;
}