https://www.luogu.org/problem/P1441
题目描述
现有n个砝码,重量分别为a1,a2,a3,……,an,在去掉m个砝码后,问最多能称量出多少不同的重量(不包括0)。
请注意,砝码只能放在其中一边。
输入格式
输入文件weight.in的第1行为有两个整数n和m,用空格分隔
第2行有n个正整数a1,a2,a3,……,an,表示每个砝码的重量。
输出格式
输出文件weight.out仅包括1个整数,为最多能称量出的重量数量。
输入输出样例
输入 #1
复制
3 1
1 2 2
输出 #1
复制
3
思路:枚举 [ 0 , 2 n − 1 ] [0,2^{n}-1] [0,2n−1]共 2 n 2^{n} 2n种状态,若某个状态的二进制表示含有 n − m n-m n−m个 1 1 1,那么它二进制为 1 1 1的位就是我们要选取的砝码的标号,利用 b i t s e t bitset bitset来计算答案, b i t s e t [ i ] = 1 bitset[i]=1 bitset[i]=1表示用这些砝码可以表示出重量 i i i,初始化需要令 b i t s e t [ 0 ] = 1 bitset[0]=1 bitset[0]=1,那么对于选取的砝码 a [ j ] a[j] a[j],只需要令: b i t s e t = b i t s e t ∣ ( b i t s e t < < a [ j ] ) bitset=bitset|(bitset<<a[j]) bitset=bitset∣(bitset<<a[j]),那么 b i t s e t bitset bitset中 1 1 1的个数就是能表示出来的重量(答案要减去 1 1 1 因为 0 0 0不算在内)。
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
int n,m;
int a[25];
int main()
{
scanf("%d %d",&n,&m);
for(int i=0;i<n;i++)
scanf("%d",&a[i]);
int times=1<<n;
int ans=0;
for(int i=0;i<times;i++)
{
if(__builtin_popcount(i)==n-m)
{
bitset<2005> b;
b[0]=1;
for(int j=0;j<n;j++)
if(i&(1<<j))
b|=b<<a[j];
ans=max(ans,(int)b.count());
}
}
printf("%d\n",ans-1);
return 0;
}