首页 > 代码库 > UVA10313- Pay the Price

UVA10313- Pay the Price

题意:有关用硬币凑成所需面值的组合数。

1、只有N,表示使用个数从1 - N的硬币凑成面值为N的组合数

2、N,L1,表示使用个数从1 - L1的硬币凑成面值为N的组合数

3、N,L1,L2,表示用个数从L1 - L2的硬币凑成面值为N的组合数


思路:这题用到了Ferrers图像的性质,即将整数N拆分成不超过n个数之和的拆分数的方案数与将整数N拆分成若干数但都不大于n的方案数是相同的。

对于这到题目就可以这样转换,用不超过j个硬币构成面值为i的方案数等于用不超过j面值的硬币构成面值为i的方案数相同。

所以d[i][j]表示用不超过j面值的硬币构成面值为i。当选择了j面值的硬币构造i的方案数为d[i - j][j],不选择的话为d[i][j - 1];


状态转移方程:d[i][j] = d[i - j][j] + d[i][j - 1]


有关Ferrers图像的性质:Ferrers图像性质


#include <iostream>
#include <cstdio>
#include <cstring>

using namespace std;

const int MAXN = 305;
const int N = 300;

char s[MAXN];
int n, l1, l2;
long long sum, d[MAXN][MAXN]; 

void dp() {
    memset(d, 0, sizeof(d)); 
    d[0][0] = 1;
    for (int i = 0; i <= N; i++) 
        for (int j = 1; j <= N; j++) {
            if (i >= j)   
                d[i][j] = d[i - j][j] + d[i][j - 1];
            else
                d[i][j] = d[i][j - 1];     
        }
}

int main() {
    dp();
    while (gets(s) != NULL) {
        int num = sscanf(s, "%d %d %d", &n, &l1, &l2); 
        l1 = l1 > N ? N : l1;
        l2 = l2 > N ? N : l2;
        sum = 0;
        if (num == 1) 
            sum = d[n][n];  
        else if (num == 2) 
            sum = d[n][l1];  
        else
            sum = d[n][l2] - d[n][l1 - 1]; 

        printf("%lld\n", sum);
    }
    return 0;
}