本题是一个完全背包问题,但需要将题目中的问题进行转换。题目中要求最小的等价货币系统的m值。那么其实就是求原有的货币序列里面有哪些数是可以被其他数表示出来的,那么这些数就是不必要存在的数。又有肯定是小的数可以组合成大的数,所以可以首先对序列进行一个排序。
然后对于数的排除其实就相当于某个数可以用无数次,求这些数可以组成的数。这就和完全背包很像了吧,那么我们建立一个一维dp,用来表示在某个数下能够组成的数,能的话是1不能是0所以初始全部复制成0,对于0赋值成1。然后当前的数能否组成j这个数一方面取决于之前的数能否如果另一方面取决于j-a[i]在之前能否组成。那么递推式就出来了。每次判断这个数在之前是否能被表示出来,如果能将个数减一即可。
#include <bits/stdc++.h> using namespace std; int dp[25000+10]; int a[100+10]; int main() { int T; cin>>T; while (T--) { int n; cin>>n; for (int i=1;i<=n;i++) { cin>>a[i]; } memset(dp, 0, sizeof(dp)); dp[0] = 1; int ans = n; sort(a+1, a+n+1); for (int i=1;i<=n;i++) { if (dp[a[i]]) { ans--; continue; } for (int j=a[i];j<=a[n];j++) { dp[j] = dp[j]||dp[j-a[i]]; } } cout<<ans<<endl; } return 0; }