HDU2069 - Coin Change - 基础dp(经典硬币问题)

Time Limit: 1000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)

Problem Description
Suppose there are 5 types of coins: 50-cent, 25-cent, 10-cent, 5-cent, and 1-cent. We want to make changes with these coins for a given amount of money.

For example, if we have 11 cents, then we can make changes with one 10-cent coin and one 1-cent coin, or two 5-cent coins and one 1-cent coin, or one 5-cent coin and six 1-cent coins, or eleven 1-cent coins. So there are four ways of making changes for 11 cents with the above coins. Note that we count that there is one way of making change for zero cent.

Write a program to find the total number of different ways of making changes for any amount of money in cents. Your program should be able to handle up to 100 coins.
 
Input
The input file contains any number of lines, each one consisting of a number ( ≤250 ) for the amount of money in cents.
 
Output
For each input line, output a line containing the number of different ways of making changes with the above 5 types of coins.
 
Sample Input
 
11
26
Sample Output
 
4
13
Author
Lily
 
Source

题目大意:

有5种面值的硬币,分别为1分,5分,10分,25分,50分,输入金额x,输出组合方案的数量,其中x\leqslant 250,硬币数量num \leqslant 100

题目分析:

如果使用暴力,可以枚举各种面值硬币的数量,判断是否等于x,枚举次数为\frac{x}{1}\times \frac{x}{5}\times \frac{x}{10} \times\frac{x}{25}\times\frac{x}{50}.

如果不限制数量,那么我们很快就能发现转移方程:f[i] = f[i] + f[i - val]  ,val为面值

比如,当面值为1时,转移方程为:f[i] = f[i] + f[i - 1],那么我们只要根据面值依次进行计算子问题的状态,这里注意面值计算的先后顺序是没关系的。

那么代码就是这样子:

#include <cstdio>
#include <iostream>
using namespace std;
const int N = 300;
int f[N];
int val[] = {1, 5, 10, 25, 50};
void solve(){
    f[0] = 1;
    for (int i = 0; i < 5; ++ i){
        for (int j = val[i]; j < N; ++ j)
            f[j] += f[j - val[i]];
    }
}
int main()
{
    solve();
    int x;
    while (~ scanf("%d", &x)){
        printf("%d\n", f[x]);
    }
    return 0;
}

但是题目限制了硬币数量,我们发现一维dp做不了,因为上述dp没有记录转移的细节,于是我们要多定义一维状态用于记录细节,所以我们可以定义状态为f[i][j]表示金额i用j个硬币组合的方案数。

那么我们可以很容易地得出状态转移方程,f[i][j] = f[i][j] + f[i - val][j - 1](金额i - val再加上一个面值为val的硬币就可以凑出金额i),其中val为面值,初始状态f[0][0] = 1(0个硬币凑出0分为1个方案)

代码:

#include <cstdio>
#include <iostream>
using namespace std;
const int N = 300;
const int num = 110;
int f[N][num];
int ans[N];
int val[] = {1, 5, 10, 25, 50};
void solve(){
    f[0][0] = 1;
    for (int i = 0; i < 5; ++ i){
        for (int j = 1; j < num; ++ j){
            for (int k = val[i]; k < N; ++ k) {
                f[k][j] += f[k - val[i]][j - 1];
            }
        }
    }
}
int main()
{
    solve();
    for (int i = 0; i <= 250; ++i){
        for (int j = 0; j <= 100; ++ j){
            ans[i] += f[i][j];
        }
    }
    int x;
    while (~ scanf("%d", &x)){
        printf("%d\n", ans[x]);
    }
    return 0;
}
发布了21 篇原创文章 · 获赞 0 · 访问量 828

猜你喜欢

转载自blog.csdn.net/tourist1412/article/details/104909689