题目:
输入有的硬币种类,求凑出指定数的最少硬币数量.
如:有2分,5分,7分的硬币,要凑出27元所需的最少硬币数量.
视频解析参考
解析:
一.确定状态
①最后一步
- 最优策略一定是k个硬币面值加起来是27
- 一定有最后一个硬币ak
- 除掉这个硬币,前面的硬币加起来是27-ak
- 27-ak的硬币数是最少的,是最优的
②子问题
- 最少用多少硬币可以拼出27-ak
- 原问题是最少用多少硬币拼出27
- 状态: f(x)=最少用多少硬币拼出x
- 最后那个硬币的ak值是多少未知,但是只有3中可能的值
二.转移方程
f[i] = min(f[i-2]+1,f[i-5]+1,f[i-7]+1)
三.初始条件和边界条件
①初始条件: f[0]=0(用转移方程计算不出来的,但是我们又需要它的定义)
②边界条件: 如果不能拼出y,就定义为正无穷
四.计算顺序
从小到大.当计算到f[x]时,f[x-2],f[x-5],f[x-7]都已经得到结果了.
solution:
#include <iostream>
#include <vector>
#define MAX 27
const int inf = (int) 1e9+7;
using namespace std;
int main()
{
int D[MAX+1];//D[i]表示拼出i元需要的最少硬币数量
D[0] = 0;
//输入指定的硬币值
vector<int> vec;
int k;
while(cin>>k)
{
vec.push_back(k);
if(cin.get()=='\n')
break;
}
int n = vec.size();
int i,j;
//D[1],D[2]...
for(i = 1;i<=27;i++)//拼出i元
{
D[i] = inf;//初值都设置为无穷大
//最后一步
for(j=0;j<n;j++)//有n中硬币;试最后一枚硬币是多大;每一步尝试3种硬币
{
if(i>=vec[j] && D[i-vec[j]]!=inf)
D[i] = min(D[i-vec[j]]+1,D[i]);//保证求当前值的时候用到的值都已经求解出来了
}
}
if(D[27] == inf) D[27] = -1;
cout<< D[27]<<endl;
return 0;
}