贪心法解决硬币问题缺陷
在最少硬币问题中,贪心法的操作是:每次都选出最大的硬币,从大到小的进行整除.然而这种方法带有缺陷,例如硬币面值比较奇怪,1,2,4,5,6支付9元,贪心的出结论是6,2,1三个硬币,然后正确答案却是5,4.
判断标准是任意面值硬币大于比它小的所有硬币之和.我的理解是满足这个定理时,因为硬币足够大,可以覆盖到其它更小的硬币,从而确保每次选择都是局部最优的。不满足时可能会在选择硬币时会选择ci,导致需要3枚硬币,但如果选择ci-1可能再加个ci-2就能得到解了.
动态规划解决硬币问题
定义数组int Min[Money] 表示每个金额所需最少硬币数量,如何递推的计算硬币数量呢?
5种面值: 1 5 10 25 50
方法1(错误的):Min[0]=0 (0元不需要硬币) Min[1]=1 ...Min[5]=2(5个1元 1个5元) 我想只要将所有的少一个这种类型的情况相加不就行了吗 代码如下
int type[] = { 1,5,10,25,50 };
void solve(int num )
{
vector<int>Min(num + 1,0);
Min[0] = 0; Min[1] = 1;
for (int i = 2; i <= num; i++)
{
for (int j = 0; j < sizeof(type) / sizeof(int); j++)
{
if (i < type[j])
break;
Min[i] += Min[i - type[j]] ;
}
}
}
但当遍历到6时出了问题 Min[6]+=Min[1],Min[6]+=Min[5]--->Min[6]=3 但我们知道结果应该是2啊(6个1 1个1+1个五)
原因分析: Min[6]+=Min[1]时表示1个1+1个五 Min[6]+=Min[5]时表示 6个1和 1个1+1个五,这样的话有些情况就会多次计算
方法二:从面值入手,从小到大考虑每种面值的最优解
void solve2(int num)
{
vector<int>Min(num + 1, 0);
Min[0] = 0; Min[1] = 1;
for (int j = 0; j < sizeof(type) / sizeof(int); j++)
{
for (int i = 2; i <= num; i++)
{
if (i < type[j])
break;
Min[i] = min(Min[i - type[j]] + 1,Min[i]);
}
}
}