1. 程式人生 > >【動態規劃】之硬幣找零問題(難度:1星)

【動態規劃】之硬幣找零問題(難度:1星)

#include <stdio.h>
/**
 * 原題:
 * 假設有幾種硬幣,如1塊、3塊、5塊,並且數量無限。 * 請找出能夠組成某個數目的找零所使用最少的硬幣數。 */
#define MIN(x,y) (x<y?x:y)


#define INF 50000   //一個很大的值,這裡可看作無限大
#define N 5         //5種硬幣
#define K 22         //目標為Kstatic int a[N] = {1,3,5,6,7};     //每種硬幣的面值
/**
 * 我的思路如下 * 設子問題為:請求出用N種硬幣,能夠組成目標數值k(k<=K)
的最小硬幣數minSum * 找出邊界:顯然k=0,minSum=0,因為湊夠0元需要的硬幣數肯定是0 */ //最容易想到的是遞迴 int solve_1(int k){ if (k == 0) return 0; int minSum = INF; for (int i = 0; i < N; ++i) { //如果當前硬幣面值不大於目標值,比較並求出最小的硬幣數 if (k >= a[i]) { minSum = MIN(minSum, solve_1(k - a[i]) + 1); } } return minSum;
} //solve_1基礎上可以加一個記憶陣列 static int memo[K+1]; int solve_2(int k){ if (memo[k] < INF) return memo[k]; if (k == 0) return memo[k] = 0; int minSum = INF; for (int i = 0; i < N; ++i) { //如果當前硬幣面值不大於目標值,比較並求出最小的硬幣數 if (k >= a[i]) { minSum = MIN(minSum, solve_2(k - a[i]) + 1
); } } return memo[k] = minSum; } //改良solve_2成為遞推 static int minSum[K+1]; int solve_3(){ minSum[0] = 0; for (int i = 1; i <= K; ++i) { minSum[i] = INF; } for (int i = 1; i <= K; ++i) { for (int j = 0; j < N; ++j) { //如果當前硬幣面值不大於目標值,比較並求出最小的硬幣數 if (i >= a[j]){ minSum[i] = MIN(minSum[i], minSum[i-a[j]] + 1); } } } return minSum[K]; } int main() { printf("solve_1:%d\n", solve_1(K)); for (int i = 0; i < K+1; ++i) { memo[i] = INF; } printf("solve_2:%d\n", solve_2(K)); // for (int i = 0; i < K+1; ++i) { // printf("%d ", memo[i]); // } printf("\nsolve_3:%d\n", solve_3()); // for (int i = 0; i < K+1; ++i) { // printf("%d ", minSum[i]); // } return 0; }

執行結果:

solve_1:4
solve_2:4
solve_3:4