蓝桥杯A组 糖果(暴力枚举)

试题 I: 糖果 时间限制: 1.0s 内存限制: 256.0MB 本题总分:25 分
【问题描述】
糖果店的老板一共有 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。

暴力是解决不了问题的!

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <vector>
#include <queue>
#include <algorithm>
using namespace std;
vector<int>v[105],path;	//v存糖果,path为dfs时生成的路径 
int visit[105],mp[105];	//visit标记糖果,mp标记口味
int N,M,K;	//N为糖果包数,M为口味数,K为每包糖果含有的糖果数 
int ans=9999;
void dfs(int n){
	if(n>ans||path.size()<M&&n==N)return;	//剪枝,如果当前取的糖果包数n比已知最小的解大,就没有必要继续走下去了,直接剪枝;当n==N说明取了N包糖果还没有解同样剪枝 
	if(path.size()==M){	//满足M中口味糖果
		if(n<ans)ans=n;	//如果当前的解比ans小,则更新ans=n 
		return;	//该路径满足一组解是就可以剪枝了 
	}
	for(int i=0;i<N;i++){	//遍历每一包糖果 
		if(visit[i]==0){	//如果第i包还没取过 
			for(int j=0;j<K;j++){	//遍历第i包里面所有的糖果 
				if(mp[v[i][j]]==0){	//如果口味v[i][j]还没有 
					path.push_back(v[i][j]);//将口味v[i][j]加到path中 
					mp[v[i][j]]=1;	//标记糖果v[i][j]有了 
				}
			}
			n++;	//目前已取的糖果包数+1 
			visit[i]=1;	//标记第i包糖果已取 
			dfs(n);	//继续递归 
			n--;	//回溯,标记为原来的状态 
			visit[i]=0;	// 回溯,标记为原来的状态 
			for(int j=K-1;j>=0;j--){	//回溯,因为上面取糖果的时候是从前往后取的,所以从后往前删(参考栈的操作)	
				if(path.back()==v[i][j]){
					path.pop_back(); //回溯,把糖果放回去 
					mp[v[i][j]]=0;	// 回溯,标记为原来的状态 
				}
			}
		}
	}
}
int main(){
	cin>>N>>M>>K;
	for(int i=0;i<N;i++){ 
		for(int j=0;j<K;j++){
			int x;
			scanf("%d",&x);
			v[i].push_back(x);
		}
	}
	dfs(0);
	if(ans==9999)ans=-1;//如果没有解,则ans还是9999,-1表示解不存在 
	cout<<ans;	//打印结果 
	return 0;
}
  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值