【luogu P1441】【状压DP】砝码称重

砝码称重

luogu P1441 砝码称重


题目

在这里插入图片描述
输入

3 1
1 2 2

输出

3

在这里插入图片描述


解题思路

用二进制枚举出所有的选数方案
然后出现了一个神奇的东西 bitset
然后。出现了一个更加神奇的东西
bitset<>s
s |= s << a[j]
这里是把s的每一位当做当前位的数能不能被拼出来,比如 s[3] = 1 表示 3 可以被拼出来
那么这是多一个 1 的砝码,3 + 1 = 4 等于第3位的一向前移动 1 位,移到第 4 位表示 4 可以被拼出来
再举一个2的例子直观一点
在这里插入图片描述


Code

#include <bits/stdc++.h>

using namespace std;

int n, m, ans, a[30], w[1 << 22];
bitset<2010> s;

int lowbit(int x) {  //取出 x 的最后一个1(x = 18(10010), lowbit(x) = 10)
	return (x & -x);
}

int main() {
	scanf("%d %d", &n, &m);
	for(int i = 1; i <= n; i ++) scanf("%d", &a[i]);
	for(int i = 1; i < (1 << n); i ++) {  //枚举所有情况
		w[i] = w[i - lowbit(i)] + 1;  //计算有多少个 1(选了多少数)(有点DP?)
		if(w[i] == n - m) {
			s.reset();  //清空
			s[0] = 1;  //初始化,注意 0 不能算作砝码拼出来的
			for(int j = 1; j <= n; j ++)
				if(i & (1 << (j - 1)))  //第 j 个砝码被选了
					s |= s << a[j];
			ans = max(ans, (int)s.count() - 1);
		}
	}
	printf("%d", ans);
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值