蓝桥杯2017年第八届-分考场

本文详细解析了一种基于回溯算法的考试分考场问题解决方案,通过递归与剪枝技术,实现了最小化所需考场数量的目标。适用于需要公平分配资源或解决类似图着色问题的场景。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题目描述:

n个人参加某项特殊考试。
为了公平,要求任何两个认识的人不能分在同一个考场。
求是少需要分几个考场才能满足条件。

输入描述:

第一行,一个整数n(1<n<100),表示参加考试的人数。
第二行,一个整数m,表示接下来有m行数据
以下m行每行的格式为:两个整数a,b,用空格分开 (1<=a,b<=n) 表示第a个人与第b个人认识。

输出描述:

一行一个整数,表示最少分几个考场。

输入样例:

5
8
1 2
1 3
1 4
2 3
2 4
2 5
3 4
4 5

输出样例:

4

核心思想:

类似于图着色问题
回溯算法:
利用递归,暴力枚举每一种分配方案。如果当前方案可能得出的解已经不可能优于最优解,则及时返回(即剪枝)。
细节见代码。

代码如下:

#include<cstdio>
#include<cstdlib>
#include<iostream>
#include<algorithm>
#include<vector>
using namespace std;
typedef long long ll;
const int N=110;
int a[N];
vector<int>mp[N];
int ans=100;
void dfs(int k,int n)
{
	int mx=0;
	for(int i=1;i<k;i++)
		mx=max(mx,a[i]);
	if(mx>=ans)//mx不优于当前最优解,剪枝 
		return;
	if(k>n)//所有人安排完毕 
	{
		ans=min(ans,mx);
		return;
	}
	for(int i=1;i<=mx;i++)//依次判断第k个人能否放在i考场中 
	{
		int l=mp[k].size(),flag=0;
		for(int j=0;j<l;j++)//判断第i个考场中是否有k的熟人 
		{
			if(a[mp[k][j]]==i)//k的第j个熟人在考场i中,则k不能放在第i个考场中 
			{
				flag=1;
				break;
			}
		}
		if(!flag)//第i个考场中没有k的熟人,k可以放在第i个考场中,递归此方案 
		{
			a[k]=i;
			dfs(k+1,n);
		}
	}
	a[k]=mx+1;//第k个人放到全新的一个考场 
	dfs(k+1,n);
	return;
}
int main()
{
	int n,m,x,y;
	cin>>n>>m;
	for(int i=1;i<=m;i++)
	{
		scanf("%d%d",&x,&y);
		//回溯的时候,例如,3认识7,给3分配考场的时候,7还没有分配,
		//但是在前面递归的时候给7分配了,导致3躲避了上次考试的7。
		//由于递归的原因,小的认识大成为了不必要的干扰项 
		//解决方法就是,将无向图存为大认识小,而小不认识大的有向图,
		//分配的时候先分配小的,大的还未分配,不需要考虑避嫌大的 
		if(x>y)
			mp[x].push_back(y);
		else if(x<y)		
			mp[y].push_back(x);
	}
	dfs(1,n);
	printf("%d\n",ans);
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值