【問題描述】
母牛們不但創建了他們自己的政府而且選擇了建立了自己的貨幣系統。[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;
}
如果是求完全揹包的可靠性問題,也可以使用相同的方法獲得。