题目描述:
糖果店的老板一共有 M 种口味的糖果出售。为了方便描述,我们将 M 种 口味编号 1 ∼ M。
小明希望能品尝到所有口味的糖果。遗憾的是老板并不单独出售糖果,而 是 K 颗一包整包出售。
幸好糖果包装上注明了其中 K 颗糖果的口味,所以小明可以在买之前就知 道每包内的糖果口味。
给定 N 包糖果,请你计算小明最少买几包,就可以品尝到所有口味的糖 果。
输入:
第一行包含三个整数 N、M 和 K。
接下来 N 行每行 K 这整数 T1, T2, · · · , TK,代表一包糖果的口味
(对于 30% 的评测用例,1 ≤ N ≤ 20 。
对于所有评测样例,1 ≤ N ≤ 100,1 ≤ M ≤ 20,1 ≤ K ≤ 20,1 ≤ Ti ≤ M 。)
输出:
一个整数表示答案。如果小明无法品尝所有口味,输出 −1。
样例输入:
6 5 3
1 1 2
1 2 3
1 1 3
2 3 5
5 4 2
5 1 2
样例输出:
2
思路:
数位DP,动态规划(DP)的一种,在本题中表示为使用二进制表示糖果情况,第i位上为0代表第i种糖果不能吃到,为1则代表能吃到。
用a[n]表示在二进制数为n时需要的最少糖果袋数,f[n]表示初始的n个糖果袋的二进制数,定义maxn等于最终的二进制数。
状态转移方程:a[j|f[i]]=min(a[j|f[i]],a[j]+1)
#include <bits/stdc++.h>
using namespace std;
const int N=1<<20;
int n,m,k,a[N],f[110];
int main(){
scanf("%d%d%d",&n,&m,&k);
int maxn=(1<<m)-1;
for(int i=0;i<=maxn;i++)a[i]=200;
for(int i=0;i<n;i++){
int x;
for(int j=0;j<k;j++){
scanf("%d",&x);
f[i]|=1<<(x-1);
}
a[f[i]]=1;
}
for(int i=0;i<n;i++){
for(int j=1;j<=maxn;j++){
if(a[j]!=200){
a[j|f[i]]=min(a[j|f[i]],a[j]+1);
}
}
}
if(a[maxn]==200)cout<<-1;
else cout<<a[maxn];
}