蓝桥杯2019-省赛-C/C++-A组I题

状态压缩dp

题目

糖果

【问题描述】

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

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

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

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

【输入格式】

第一行包含三个整数 N、M 和 K。

接下来 N 行每行 K 这整数 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 ≤ 100,1 ≤ M ≤ 20,1 ≤ K ≤ 20,1 ≤ Ti ≤ M。

代码

 1 #include<iostream>
 2 #include<cmath> 
 3 #include<string.h>
 4 using namespace std;
 5 int main(){
 6     int n,m,k;
 7     cin>>n>>m>>k;
 8     int dp[1<<m+5];
 9     int goods[n];
10     int ss,s;
11     memset(dp,-1,sizeof(dp));//dp数组初始化 
12     for(int i=0;i<n;i++){
13         ss=0;
14         for(int j=0;j<k;j++){
15             cin>>s;
16             ss|=(1<<(s-1));//用二进制形式表示货物的状态,比如,
17                            //总共有5种糖果,那么我们的二进制位数应该是5位
18                            //一袋糖果有3个糖果,他们分别是1,2,3,那么对应
19                            //的状态就是00111 
20         }
21         goods[i]=ss;
22         dp[ss]=1;
23     }
24     for(int i=0;i<n;i++){
25         for(int j=0;j<(1<<m);j++){
26             if(dp[j]==-1) continue;//无该状态,返回 
27             if(dp[j|goods[i]]==-1) //新组合的状态的信息未记录,记录下 
28                 dp[j|goods[i]]=dp[j]+dp[goods[i]]; 
29             else//新组合的状态遇见更好的方案,未更新,更新下 
30                 dp[j|goods[i]]=min(dp[j|goods[i]],dp[j]+dp[goods[i]]); 
31         }
32     }
33     cout<<dp[(1<<m)-1]<<endl;//输出要所有类型糖果的最少的产品数 
34 }

 

posted @ 2020-02-12 21:08  Mem_Ocean  阅读(413)  评论(0)    收藏  举报