蓝桥杯国赛真题【分考场】

题意

在这里插入图片描述

思路

由于数据比较小,而且题意中的“认识”仅限于两个人之间,没有传递的意思,我们可以用爆搜来写,具体来看,我们先准备至少n个考场,从第一位考生开始爆搜。对于当前枚举的考生x,我们有两种选择,第一个:我们将当前考生放置已经存在考生的考场y(枚举已经存在考生的考场)中,满足该选择的条件是:考场y中的所有考生和当前枚举的考生均不认识。第二个:我们使用一个没有考生的教室z,将当前考生x放入进考场z。

算法

具体实现的话,我们用爆搜即可,定义函数void dfs(int u, int cnt),其中u是当前枚举的考生,cnt是用了多少个考场,两种情况对应在代码中寻找即可,这里额外讲一下本题的重点,如果当前使用的考场不小于我们的答案,我们应该立即返回,即在dfs函数中return,这是一个很优秀的剪枝技巧,此外,如果本题的剪枝条件为:使用的考场大于我们的答案。会导致本题最后一个样例因为超时而过不了本题,所以我们应当选用尽可能优秀的剪枝。

AC代码(C++)

#include <iostream>
#include <cstring>
#include <algorithm>
#include <vector>

using namespace std;

const int N = 110;

int n, m, res = N;
bool re[N][N];
vector<int> rooms[N];

void dfs(int u, int cnt) {
	if(cnt >= res) return ;
	if(u == n + 1) {
		res = cnt;
		return ;
	}
	
	for(int i = 1; i <= cnt; i ++) { // 枚举当前考场是否可以放入u号考生 
		bool flag = true;
		for(int j = 0; j < rooms[i].size(); j ++) {
			if(re[u][rooms[i][j]]) {
				flag = false;
				break;
			} 
		}
		
		if(flag) {
			rooms[i].push_back(u);
			dfs(u + 1, cnt);
			rooms[i].pop_back();
		}
	}
	
	rooms[cnt + 1].push_back(u);
	dfs(u + 1, cnt + 1);
	rooms[cnt + 1].pop_back();
}

int main() {
	cin >> n >> m;
	for(int i = 1; i <= n; i ++) re[i][i] = true;
	while(m --) {
		int a, b;
		cin >> a >> b;
		re[a][b] = re[b][a] = true;
	}
	
	dfs(1, 0);
	
	cout << res << "\n";
	return 0;
}
posted @ 2023-04-04 14:36  openallzzz  阅读(13)  评论(0编辑  收藏  举报  来源