题意:
用1、5、10、25、50 这五个面值的钱币去凑给定的金额n,问有多少种方案
思路:
定义状态: d(i, j)表示用前 i 种面值凑 j 共有多少种不同的方案
初始状态:
题目规定0金额有1种,d(1-5, 0) = 1;
前1中面值的凑法只有1种:d(1, 1-n) = 1;
状态转移:
- 当j < a[i], d(i, j) = d(i - 1, j - 1);
- 当j >= a[i],d(i, j) = d(i - 1, j)+ ∑ k = 1 j / a [ i ] \sum_{k=1}^{j/a[i]} ∑k=1j/a[i]d(i - 1, j - k*a[i]);
先打表,不然超时
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int INF = 0x3f3f3f3f;
typedef long long LL;
const int maxn = 7500;
int money[6] = {0, 1, 5, 10, 25, 50};
int d[6][maxn+1];
void dp(){
for(int i = 0; i <= maxn; ++i) d[1][i] = 1;
for(int i = 0; i <= 5; ++i) d[i][0] = 1;
for(int i = 2; i <= 5; ++i){
for(int j = 1; j <= maxn; ++j){
if(j < money[i]) d[i][j] = d[i-1][j];
else{
d[i][j] = d[i-1][j];
for(int k = 1; k <= j/money[i]; ++k){
d[i][j] += d[i-1][j-k*money[i]];
}
}
}
}
}
int main()
{
freopen("in.txt","r",stdin);
dp();
int n;
while(scanf("%d",&n) == 1){
//dp();
// for(int i = 1; i <= 5; ++i){
// for(int j = 1; j <= 26; ++j) printf("%d ", d[i][j]);
// puts("");
// }
printf("%d\n", d[5][n]);
}
fclose(stdin);
return 0;
}