问题:有n种硬币,面值分别为V1,V2……Vn,每种都有无限多。给定非负整数s,可以选用多少个硬币,使得面值之和恰好为s?输出硬币数目最大值。
分析:这题依然是DP的入门题。先说说我在考虑时候的问题,第一就是刚开始认为硬币的值是状态,结果怎么想都想不通,第二就是在看紫书时对于他提出的通过赋一个非常小的初值以达到检验该路是否到达终点,一直想不通,最终在某汶神的帮助下才脱坑——这题确实挺水的= =。然后说下解题思路,本题的关键在于如何设置状态以及检测是否能够到达终点,前一个问题的解决办法就是设置面值和为状态,所以状态方式就为选择某个硬币,以当前面值和减去该硬币面值,得到新的面值和,即新的状态,第二个问题则需要将以面值和为下标的数组的下标为0的位置设置为0,其余设置为-1,并在DP时将状态设置为非常小的数,这样,当某路能够到达终点时,则可以取到0,并可以累加下去,而无法到达终点的路怎么无论怎么加都无法大于0
代码:
#include<cstdio>
#include<cstring>
int d[1000],v[10];
int max(int a, int b)
{
return a > b ? a : b;
}
int dpmax(int s,int n)
{
if (d[s] != -1)
return d[s];
d[s] = -10000;//用于设定不能走到终点的路肯定小于能走到终点的路
for (int i = 0;i < n;i++)
if (s >= v[i])//等号很关键
d[s] = max(d[s], dpmax(s - v[i], n)+1);
return d[s];
}
int main()
{
int n, s, i;
while (scanf("%d%d", &n, &s) != EOF)
{
for (i = 0;i < n;i++)
scanf("%d", &v[i]);
memset(d, -1, sizeof d);
d[0] = 0;//用于辨别该路能否走到终点
printf("%d\n", dpmax(s, n));
}
return 0;
}