牛客——货币系统(思维+DP)
题意:
求一个集合b,使得该集合能够表示出的数与给出的集合a能够表示出的数相同,输出该集合最少有多少个元素。
思路:
首先我们可以知道,如果集合里的一个数可以由集合里的其他数表示出来,那么前者就没有存在的必要了。
所以,在最优解里,集合b里面的元素一定是在集合a里的,因为只有这样,才能最小化集合b的元素个数。可以这样想,如果集合b里面的某个元素b[1]是由a[1] + a[2] 而来,而且a[1]、a[2]又可以由集合b的元素表示出来,那么b[1]的存在就没有意义了。
综上,可以从小到大排序后,判断a[i]能否被前面的数表示出来,如果可以的话,一定不选这个数;否则,一定要选这个数。之后借鉴完全背包的思想,进行状态转移,统计个数即可。
代码:
#pragma GCC optimize(2)
#include<bits/stdc++.h>
typedef long long ll;
using namespace std;
typedef pair<int,int>PII;
inline ll read(){
ll x = 0, f = 1;
char ch = getchar();
while(ch < '0' || ch > '9'){
if (ch == '-')
f = -1;
ch = getchar();
}
while(ch >= '0' && ch <= '9'){
x = (x<<1) + (x<<3) + (ch^48);
ch = getchar();
}
return x * f;
}
const int maxn=25100;
int n,a[maxn];
bool dp[maxn];
int main(){
int t=read();
while(t--){
n=read();
for(int i=1;i<=n;i++) a[i]=read();
sort(a+1,a+1+n);
memset(dp,0,sizeof dp);
dp[0]=1;
int res=0;
for(int i=1;i<=n;i++){
if(!dp[a[i]]) res++;
for(int j=a[i];j<=a[n];j++)
dp[j]|=dp[j-a[i]];
}
cout<<res<<endl;
}
return 0;
}

京公网安备 11010502036488号