题目描述:
糖果店的老板一共有 M 种口味的糖果出售。为了方便描述,我们将 M 种 口味编号
1
∼
M
1 ∼ M
1∼M。
小明希望能品尝到所有口味的糖果。遗憾的是老板并不单独出售糖果,而 是 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
1≤N≤20。
对于所有评测样例,
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
1≤N≤100,1≤M≤20,1≤K≤20,1≤Ti≤M。
解题报告:
我们用二进制形式表示每袋糖果的状态
例如: 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;
}