分考场问题
这个问题 多次遇到过,看完别人的思路才明白,记录一下(我思路好乱。。。)
问题描述
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
思路:如果一个学生想要进入考场,他需要逐个看看这个考场里的所有人他是否认识,如果有一个认识,那么换下一个考场。如此重复。如果所有考场都枚举完了,还没有符合的考场,那就新开一个考场。
首先定义一个数组g用来维护考生之间的关系,a,b有关系:g[a][b]=g[b][a]=1;
再定义一个数组p用来储存考场里的考生,当新来一个考生X时,我们需要知道这个考场里有多少考生,然后在一一和此考生X对比,看是否符合。
详解看代码:
#include <stdio.h>
#include <algorithm>
using namespace std;
int g[110][110],p[110][110];
int n,num=110;
void dfs(int x,int kn) //x考生数 kn考场数
{
if(kn>=num) return;//剪枝
if(x>n)
{
num=min(num,kn);
return;//分完结束,返回
}
for(int i=1; i<=kn; i++) //枚举考场
{
int k=0;
while(p[i][k] && !g[x][p[i][k]]) k++;
//i考场没有人 直接退出while 进入if语句 说明这个考生可以在这个考场
//i考场有人 如果是因为考生与这个考场中的某个人认识而退出的话 p[j][k]肯定是为1 不执行if语句 接着看下一个考场
//i考场有人 是因为观察完此考场中所有的学生都与x考生互不认识推出的,那么if语句执行
if(p[i][k]==0)
{
p[i][k]=x;
dfs(x+1,kn);
p[i][k]=0;
}
}
p[kn+1][0]=x; //遍历完所有的考场,未符合条件,重开一个考场
dfs(x+1,kn+1);
p[kn+1][0]=0;
}
int main()
{
int m,a,b;
scanf("%d%d",&n,&m);
for(int i=1; i<=m; i++)
{
scanf("%d%d",&a,&b);
g[a][b]=g[b][a]=1;
}
dfs(1,1);
printf("%d
",num);
return 0;
}
在这里致谢大佬:https://blog.csdn.net/baidu_41907100/article/details/88367366