//最大公约数不是1则只能凑出其倍数
//若是一,则dp
//集合表示:只考虑前i个物品,能否凑数j
//状态bool值
//计算:多重背包(不选第i件物品则为f[i-1][j],要选则为 |上f[i][j-w])
// f[i][j] = f[i][j] | f[i][j-w] | f[i][j-2w] | f[i][j-3w]......
// f[i][j-w] = f[i][j-w] | f[i][j-2w]| f[i][j-3w]......
//所以f[i][j] = f[i][j]|f[i][j-w]
#include<iostream>
using namespace std;
const int maxn = 110,N=1e4+10;
int gcd(int a,int b){
if(!b)return a;
else
return gcd(b,a%b);
}
int w[N];
int n;
int f[N][N];
int main()
{
int d=0;
cin>>n;
for(int i=1;i<=n;i++){
cin>>w[i];
d = gcd(d,w[i]);
}
if(d!=1)puts("INF");
else{
f[0][0]=1;
for(int i=1;i<=n;i++){
for(int j=0;j<=N;j++){
f[i][j] = f[i-1][j];
if(j>=w[i]){
f[i][j] |=f[i][j-w[i]];
}
}
}
int res=0;
for(int i=0;i<=N;i++){
if(!f[n][i])res++;
}
cout<<res<<endl;
}
return 0;
}
优化版本
#include<iostream>
using namespace std;
const int maxn = 110,N=1e4+10;
int gcd(int a,int b){
if(!b)return a;
else
return gcd(b,a%b);
}
int w[N];
int n;
int f[N];
int main()
{
int d=0;
cin>>n;
for(int i=1;i<=n;i++){
cin>>w[i];
d = gcd(d,w[i]);
}
if(d!=1)puts("INF");
else{
f[0]=1;
for(int i=1;i<=n;i++){
for(int j=w[i];j<=N;j++){
f[j] = f[j];
f[j] |=f[j-w[i]];
}
}
int res=0;
for(int i=0;i<=N;i++){
if(!f[i])res++;
}
cout<<res<<endl;
}
return 0;
}
04-03
2031
05-10
1376
04-09
763