【问题描述】
母牛们不但创建了他们自己的*而且选择了建立了自己的货币系统。[In their own rebellious way],他们对货币的数值感到好奇。传统地,一个货币系统是由1,5,10,20或25,50和100的单位面值组成的。
母牛想知道有多少种不同的方法来用货币系统中的货币来构造一个确定的数值。举例来说,使用一个货币系统{1,2,5,10,…}产生18单位面值的一些可能的方法是:18×1,9×2,8×2+2×1,3×5+2+1等等其它。
编写一个程序来计算有多少种方法用给定的货币系统来构造一定数量的面值。保证总数将会适合long long(C/C++)和Int64(Free Pascal)。
【输入格式】
货币系统中货币的种类数目是V(1<=V<=25)。
要构造的数量钱是N(1<=N<=10000)。
第1行:两个整数V和N。
第2..V+1行:可用的货币V个整数(每行一个,每行没有其它的数)。
【输出格式】
输出文件中单独的一行包含那个可能的构造的方案数。
【输入输出样例】
输入:
3 10
1 2 5
输出:
10
解答
此问题可以抽象为完全背包可行性的方案种数问题,状态转移方程:F[i,v] = sum(F[i-1,v], F[i,v-Ci]),根据此方程不难得到如下精简的代码:
int ks_count(int *cost, int n, int spec_number) { int i = 0, v = 0, max_count = -1; int *F = NULL; F = malloc(sizeof(int) * (spec_number + 1)); memset(F, 0, sizeof(int) * (spec_number + 1)); F[0] = 1; for (i = 0;i < n;i++) { for (v = 0;v + cost[i] <= spec_number;v++) { F[v + cost[i]] += F[v]; } } max_count = F[spec_number]; #ifdef DEBUG_ARR for (i = 0;i <= spec_number;i++) { printf("%4d ", F[i]); } printf("\n"); #endif free(F); return max_count; }
如果是求完全背包的可靠性问题,也可以使用相同的方法获得。