分考场
问题描述
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
样例输入
5
10
1 2
1 3
1 4
1 5
2 3
2 4
2 5
3 4
3 5
4 5
样例输出
5
思路
此题为图的着色问题的延申问题。思想参考来源https://blog.csdn.net/li1615882553/article/details/79694958 ,图的着色问题,为图上在同一边上的两个顶点涂上不同颜色,通过dfs来回溯出所有的解。
对于此题,解决相互认识的人,分在不同的教室问题,引到图的着色问题上就是:相连的两个顶点(同一边上的两个顶点),涂不同的颜色。此题让求最少分配教室数,就转化为最少使用的颜色数。在回溯的过程中,若现在的颜色数不够涂,则num(颜色数)增加1,(ps:注意,即使现在的颜色数足够给当前的顶点上色,也要尝试新分配一个色,给当前顶点,因为此种情况可能更优(T-T)当时就没考虑这个情况,结果只通过60%,找了好久才找出来,令人头秃…)。当回溯出一种情况,则记录当前使用颜色数。后面可以剪去比这个当前记录最小使用颜色数多的情况。
c语言代码
#include<stdio.h>
int map[110][110]={0};//人与人是否认识,是=1,否=0.
int color[110]={0};//为每个人对应分的教室号
int min_num; //最小教室数
int m,n;
void init()//数据处理函数
{
int i,a,b;
scanf("%d%d",&n,&m);
min_num=n;
while(m--)
{
scanf("%d%d",&a,&b);
map[a][b]=map[b][a]=1;
}
}
int judeg(int pos,int col)//判断同一条边的两个顶点是否着同一色,即认识的两人是否分同一教室
{
int i;
for(i=1;i<=n;i++)
{
if(map[pos][i]&&color[i]!=0&&color[i]==col)return 0;//连接,并且颜色相同//即相互认是,却被分到同一教室
}
return 1;
}
void solve(int pos,int num)//num表示当前已使用的颜色,即 已使用的房间
{
int i,js=0;
if(num>=min_num)return ;//剪枝,当此种情况使用房间数已经>当前记录最小情况,返回
if(pos==n+1)//分配完成
{
if(min_num>num) min_num=num;
return;
}
for(i=1;i<=num;i++)
{
if(judeg(pos,i))
{
color[pos]=i;
solve(pos+1,num);
color[pos]=0;
}
}
//尝试开间新房 !!T-T
num++;
color[pos]=num;
solve(pos+1,num);
color[pos]=0;
}
int main()
{
init();
solve(1,0);
printf("%d",min_num);
return 0;
}