开启掘金成长之旅!这是我参与「掘金日新计划 · 2 月更文挑战」的第 2 天,点击查看活动详情
[蓝桥杯 2019 省 A] 糖果
题目描述
糖果店的老板一共有 种口味的糖果出售。为了方便描述,我们将 种口味编号 ∼ 。
小明希望能品尝到所有口味的糖果。遗憾的是老板并不单独出售糖果,而是 颗一包整包出售。
幸好糖果包装上注明了其中 颗糖果的口味,所以小明可以在买之前就知道每包内的糖果口味。
给定 包糖果,请你计算小明最少买几包,就可以品尝到所有口味的糖果。
输入格式
第一行包含三个整数 、 和 。
接下来 行每行 这整数 ,代表一包糖果的口味。
输出格式
一个整数表示答案。如果小明无法品尝所有口味,输出 。
样例 #1
样例输入 #1
6 5 3
1 1 2
1 2 3
1 1 3
2 3 5
5 4 2
5 1 2
样例输出 #1
2
提示
对于 的评测用例,。
对于所有评测样例,,,,。
蓝桥杯 2019 年省赛 A 组 I 题。
分析
这道题题意就是在给你n组数,每组数有k个,每次要选只能选择整组数,问至少要选多少组数才能覆盖1-m的所有数,这题可以很明显看出来是个状压dp,可以考虑dp[j]表示要达到状态为j的情况至少要买多少包糖果,最后输出dp[(1<<m)-1]即可,然后我们将每一包糖果的不同糖果转化为m位二进制表示,然后枚举每一种状态j,对于100个状态dp[a|j]=max(dp[a|j],dp[j]+1);(a是那100种状态),虽然但是我本来以为会超时的,结果题解过了,就很离谱。
代码
#include <iostream>
#include <cstdio>
#include <cstring>
#include <vector>
#include <algorithm>
#define ll long long
using namespace std;
const int N=110,M=21,K=21;
ll ans=0,mi,ma;
vector<int>state;
int dp[1<<M];
bool ok[K],ok1=0;
int n,m,k;//n包糖果,m个口味,每包k颗糖果。
int main(){
int te=0;
cin>>n>>m>>k;
memset(dp,0x3f,sizeof dp);
for(int i=1;i<=n;i++){
memset(ok,0,sizeof ok);
int temp=0;
for(int j=1;j<=k;j++){
int x;
cin>>x;
x--;
if(!ok[x]){
temp+=1<<x;
ok[x]=1;
}
}
if(temp==(1<<m)-1) ok1=1;
state.push_back(temp);
te|=temp;
}
if(te!=(1<<m)-1) puts("-1");
else{
dp[0]=0;
for(auto b:state){
for(int i=0;i<(1<<m)-1;i++){
dp[i|b]=min(dp[i|b],dp[i]+1);
}
}
cout<<dp[(1<<m)-1]<<endl;
}
return 0;
}