蓝桥杯2019年省赛糖果

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

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

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

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

输入描述:第一行包含3个整数N, M, K

接下来N行每行包含K个整数,表示一包糖果的口味。

其中,1<=N<=100, 1<=m<=20, 1<=K<=20。

6 5 3

1 1 2

1 2 3

1 1 3

2 3 5

5 4 2

5 1 2

输出描述

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

2

思路:状态压缩+动态规划

状态压缩:题目要求凑成所有口味的糖果,我们就需要用一个二进制数来表示已经凑成了多少种糖果。二进制数的第n位为1表示包含该糖果,例如:输入样例中的第一包糖果1,1,2,那么可以用二进制表示为00011;第一包+第二包就是00011 | 00111 = 00111.

动态规划:用dp[i]表示凑成二进制i最少需要多少包。

详细思路见代码解析:

#include <bits/stdc++.h>
using namespace std;
#define int long long
const int N = (1<<20)+10;
int n, m, k;
int dp[N], a[N];
signed main(){
	memset(dp, 0x3f3f3f3f, sizeof(dp));  //初始化dp为无穷大,表示目前这种糖果组合无法凑出 
	cin >> n >> m >> k;
	int all = (1<<m)-1;   //all可以看做全为 1 的 m 位二进制数 
	for(int i = 1; i<=n; i++){
		for(int j = 1; j<=k; j++){
			int t;
			cin >> t;
			a[i] |= (1<<(t-1));  //a[i]表示第 i 包里面的糖果组合 
		}
		dp[a[i]] = 1;  // 凑出第 i 包的糖果组合至少需要 1 包 
	}	
	for(int i = 1; i<=n; i++){    //第 i 包糖果 
		for(int j = 0; j<=all; j++){   //所有可能出现的糖果组合 
			dp[a[i]|j] = min(dp[a[i]|j], dp[j]+1);  //详细推理见下图 
		}
	}
	if(dp[all]>n) cout << -1;
	else cout << dp[all];
	return 0;
} 

 

  • 4
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值