您的位置:首页 > 其它

【动态规划】之硬币找零问题(难度:1星)

2017-12-14 22:56 274 查看
#include <stdio.h>
/**
* 原题:
* 假设有几种硬币,如1块、3块、5块,并且数量无限。
* 请找出能够组成某个数目的找零所使用最少的硬币数。
*/
#define MIN(x,y) (x<y?x:y)

#define INF 50000   //一个很大的值,这里可看作无限大

#define N 5         //有5种硬币
#define K 22         //目标为K块

static 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
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: