[蓝桥杯][2019年第十届真题]糖果(状压dp)

题目描述:
糖果店的老板一共有 M 种口味的糖果出售。为了方便描述,我们将 M 种 口味编号 1 ∼ M 1 ∼ M 1M
小明希望能品尝到所有口味的糖果。遗憾的是老板并不单独出售糖果,而 是 K 颗一包整包出售。
幸好糖果包装上注明了其中 K 颗糖果的口味,所以小明可以在买之前就知 道每包内的糖果口味。
给定 N 包糖果,请你计算小明最少买几包,就可以品尝到所有口味的糖 果。

输入:
第一行包含三个整数 N N N M M M K K K
接下来 N 行每行 K 这整数 T 1 , T 2 , ⋅ ⋅ ⋅ , T K T1, T2, · · · , TK T1,T2,,TK,代表一包糖果的口

输出:
一个整数表示答案。如果小明无法品尝所有口味,输出 −1。

样例输入:
6 5 3
1 1 2
1 2 3
1 1 3
2 3 5
5 4 2
5 1 2
样例输出:
2
【评测用例规模与约定】
对于 30% 的评测用例, 1 ≤ N ≤ 20 1 ≤ N ≤ 20 1N20
对于所有评测样例, 1 ≤ N ≤ 100 , 1 ≤ M ≤ 20 , 1 ≤ K ≤ 20 , 1 ≤ T i ≤ M 1 ≤ N ≤ 100,1 ≤ M ≤ 20,1 ≤ K ≤ 20,1 ≤ Ti ≤ M 1N1001M201K201TiM

解题报告:
我们用二进制形式表示每袋糖果的状态
例如: 10010 : 表示拥有第二种和第五种糖果。
答案求 1<<(m-1) 状态下所需最少袋数

代码展示:

#include<bits/stdc++.h>
#define LL long long
#define pii pair<int,int>
#define all(x) x.begin(),x.end()
#define mem(a, b) memset(a,b,sizeof(a))
using namespace std;
const int maxn = 1e6 + 5;
const int MOD = 1e9 + 7;

inline int read() {
	int s = 0, f = 1;
	char ch = getchar();
	while (ch < '0' || ch > '9') {if (ch == '-') f = -1; ch = getchar();}
	while (ch >= '0' && ch <= '9') {s = (s << 1) + (s << 3) + ch - '0'; ch = getchar();}
	return s * f;
}
inline void write(LL x) {
	if (x < 0) x = -x, putchar('-');
	if (x > 9) write(x / 10);
	putchar(x % 10 + '0');
}
int dp[(1 << 21)], a[105];
int main() {
	mem(dp, -1); 
	int n = read(), m = read(), k = read();
	for (int i = 1; i <= n; i++) {
		for (int j = 1; j <= k; j++) {
			a[i] |= (1 << (read() - 1));
		}
		dp[a[i]] = 1;// 此状态下仅需 1 袋
	}
	for (int i = 1; i <= n; i++) { //枚举每一袋糖果
		for (int j = 0; j < (1 << m); j++) { //枚举所有状态
			if (dp[j] == -1) continue; // 表示此状态下的糖果之前并未购买
			else if (dp[j | a[i]] == -1 ) dp[j | a[i]] = dp[j] + 1; // 表示此状态下的糖果第一次购买
			else dp[j | a[i]] = min(dp[j | a[i]], dp[j] + 1); // 表示此状态下的糖果所需最少袋数
		}
	}
	write(dp[(1 << m) - 1]);
	putchar('\n');
	return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值