动态规划的本质是将原问题分解为同性质的若干个相同子结构,以局部最优值求得最优值。它和普通递归求解好处在于可以避免大量的重复计算。求解动规需要找到问题本质的状态,利用已知状态,推出状态转移方程。有了状态转移方程,什么都好说了。
以3个硬币的价值分别为1,3,5,然后要得到值为value的最少硬币数ans为例,下面表示的意思是d(value) = ans:
d(0) = 0//方案只有1种
d(1) = 1//方案只有1种
d(2) = d(2-1)+1 = 2//依次类推,方案只有1种
d(3) = min{d(3-1)+1, d(3-3)+1} = 1 //方案有2种,需要取最少值
d(4) = min{d(4-1)+1, d(4-3)+1} = 1 //取最小值
d(5) = min{d(5-1)+1, d(5-3)+1, d(5-5)+1} = 1 //取最小值
d(6) = min{d(6-1)+1, d(6-2)+1, d(6-5)+1} = 2 //取最小值
….
以此类推
….
d(n) = min{d(n-value[0])+1, d(n-value[1])+1, d(n-value[2])+1}
从中可以得到状态转移方程为:d(n) = min{d[n-value[i]]+1}。
代码如下:
#include <iostream>
using namespace std;
#include <cstdio>
#define MAXN 1010
int Min(int x, int y)
{
return x<y?x:y;
}
int main()
{
int N, M;
int value[MAXN] = {0};
int ans[MAXN] = {0};
scanf("%d", &N);
for(int i = 0; i < N; i++)
{
scanf("%d", &value[i]);
}
scanf("%d", &M);
for(int i = 0; i <= M; i++)
{
int min = 9999;
for(int j = 0; j < N; j++) //主要用于求解在value值一定的情况下不同的组合方式的硬币最小数
{
if(i == 0)
{
ans[i] = 0;
}
else if(i >= value[j])
{
min = Min(ans[i-value[j]]+1, min);
}
}
if(i != 0)
ans[i] = min;
}
for(int i = 0; i <= M; i++)
{
cout<<ans[i]<<" ";
}
return 0;
}