P8687 [蓝桥杯 2019 省 A] 糖果

89 阅读2分钟

开启掘金成长之旅!这是我参与「掘金日新计划 · 2 月更文挑战」的第 2 天,点击查看活动详情

[蓝桥杯 2019 省 A] 糖果

题目描述

糖果店的老板一共有 MM 种口味的糖果出售。为了方便描述,我们将 MM 种口味编号 11MM

小明希望能品尝到所有口味的糖果。遗憾的是老板并不单独出售糖果,而是 KK 颗一包整包出售。

幸好糖果包装上注明了其中 KK 颗糖果的口味,所以小明可以在买之前就知道每包内的糖果口味。

给定 NN 包糖果,请你计算小明最少买几包,就可以品尝到所有口味的糖果。

输入格式

第一行包含三个整数 NNMMKK

接下来 NN 行每行 KK 这整数 T1,T2,,TKT_1,T_2, \cdots ,T_K,代表一包糖果的口味。

输出格式

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

样例 #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

提示

对于 30%30\% 的评测用例,1N201 \le N \le 20

对于所有评测样例,1N1001 \le N \le 1001M201 \le M \le 201K201 \le K \le 201TiM1 \le T_i \le M

蓝桥杯 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;
}