题解 P5020 【货币系统】
看起来这道题虽然有很多人写了题解但并没有太多严谨的数学证明。
本蒟蒻就来写一下自己考场上的思路。
我们把货币系统
那么我们首先可以猜测
但是这个结论并不好直接证明,在证明这个猜测前我们先来证明另一个猜测
证明过程
我们设
然后我们假设
那么这些元素至少存在一个不在集合
综上所述,
通过这个结论我们便可以证明
证明过程
假设存在
根据题目条件,
那么必然存在
那么也就是说
所以对于任意
那么做这道题仅仅只需要最后一个证明了,如果你到这里都看懂了的话那应该不难想到最后一个猜测就是在
那么到这里做这道题的步骤就已经显而易见了,只需要计算出
比较好想的是使用搜索算法,相信各位都会,这里就不多说了。主要讲一下使用完全背包来完成这件事。
根据常识,我们知道
那么很显然,我们可以首先对数组排个序,然后对于每一个数考虑能不能被它前面的数字所组成。
我们知道如果
那么这个样子也就是最终的解法了,个人认为这道题主要考察对集合相关概念的证明,而重点并不是动态规划,其它的题解侧重点都不太对。
最后贴出AC代码:
#include<stdio.h>
#include<algorithm>
#include<string.h>
using namespace std;
#define MAXAI 25005
#define MAXN 105
int f[MAXAI];
int a[MAXN];
int main()
{
//freopen("money.in","r",stdin);
//freopen("money.out","w",stdout);
int i,j,n,T,ans;
scanf("%d",&T);
while(T--)
{
memset(f,0,sizeof(f));
scanf("%d",&n);ans=n;
for(i=1;i<=n;i++) scanf("%d",&a[i]);
sort(a+1,a+n+1);
f[0]=1;
for(i=1;i<=n;i++)
{
if(f[a[i]])
{
ans--;
continue;
}
for(j=a[i];j<=a[n];j++)
{
f[j]=f[j]|f[j-a[i]];
}
}
printf("%d\n",ans);
}
return 0;
}