[蓝桥杯 2019 省 A] 糖果
题目
Description
糖果店的老板一共有 MM 种口味的糖果出售。为了方便描述,我们将 MM 种口味编号 11 ∼ MM。
小明希望能品尝到所有口味的糖果。遗憾的是老板并不单独出售糖果,而是 KK 颗一包整包出售。
幸好糖果包装上注明了其中 KK 颗糖果的口味,所以小明可以在买之前就知道每包内的糖果口味。
给定 NN 包糖果,请你计算小明最少买几包,就可以品尝到所有口味的糖果。
Input
第一行包含三个整数 NN、MM 和 KK。
接下来 NN 行每行 KK 这整数 T1,T2,⋯ ,TKT1,T2,⋯,TK,代表一包糖果的口味。
Output
一个整数表示答案。如果小明无法品尝所有口味,输出 −1−1。
Sample Input
6 5 3 1 1 2 1 2 3 1 1 3 2 3 5 5 4 2 5 1 2
Sample Output
2
思路
题目思路其实就是背包的思想;
只不过每包糖果需要用状态压缩;
那么转移方程就为:
$dp[j|a[i]]=min(dp[j|a[i]],dp[j]+1]);$
$a[i]$ 为第 $i$ 包糖果口味的状态, $j$ 表示当前所选的所有口味的状态;
然后要注意的是因为每包糖果只要一包,所以要用逆循环;
代码
#include<bits/stdc++.h> typedef long long ll; using namespace std; ll n,m,t; ll a[101],dp[1<<20]; int main() { memset(dp,127/3,sizeof(dp)); scanf("%lld%lld%lld",&n,&m,&t); for(ll i=1;i<=n;i++) { ll x,sum=0; for(ll j=1;j<=t;j++) { scanf("%lld",&x); sum|=1<<(x-1);//糖果口味可能有重复,所以不能用+,要用| } a[i]=sum;//预处理每包糖果的口味状态 } dp[0]=0; for(ll i=1;i<=n;i++) for(ll j=(1<<m)-1;j>=0;j--) { dp[j|a[i]]=min(dp[j|a[i]],dp[j]+1); }//就是和背包差不多的处理 if(dp[(1<<m)-1]<=100) printf("%lld",dp[(1<<m)-1]); else printf("-1"); return 0; }