资源限制
时间限制:1.0s 内存限制:256.0MB
问题描述
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
思路
可以抽象为无向图染色问题。相邻顶点不能染相同颜色,问至少要用多少种颜色。
用DFS搜索+回溯
假设 n 个人需要 kcs 个考场 ,先在 kcs 个考场 安排n 个人 如果安排不下 再增加考场数。在已知的状态下,然后去判断下一个学生是否可以在之前存在的教室,如果不可以的话,那么就新开一个教室。
通过DFS +剪枝 从所有可能情况中得到最小考场数。
提交代码
#include <iostream>
#define N 101
//关系表
int g[N][N];
//考场状态
int p[N][N];
//考场数量
int num;
//n考试人数
int n;
using namespace std;
void DFS(int x, int kcs) { //x代表当前安排了多少人,kcs代表当前所开的考场数
if (kcs >= num)return; //如果当前考场数大于总考场数(剪枝)
if (x > n) { //如果已经安排了n个人,就将当前考场设为最小考场
if(kcs<num) //比num大的都被剪掉了
num = kcs;
return;
}
for (int i = 1; i <= kcs; i++) //枚举考场
{
int k = 0;
while (p[i][k] && !g[x][p[i][k]])k++; //找到一个空位,并且该考场人无关系
//i考场没有人 直接退出while 进入if语句 说明这个考生可以在这个考场
//i考场有人 如果是因为考生与这个考场中的某个人认识而退出的话 p[i][k]肯定是为1 不执行if语句 接着看下一个考场
//i考场有人 是因为观察完此考场中所有的学生都与x考生互不认识推出的,那么if语句执行
if (!p[i][k]) { //满足条件,不认识该考场所有学生
p[i][k] = x; //将该考生放入考场
DFS(x + 1, kcs); //尝试将下一考生放入该考场
p[i][k] = 0; //回溯,尝试其他情况
}
}
p[kcs + 1][0] = x; //遍历完所有的考场 发现都不行 只能新开辟一个考场
DFS(x + 1, kcs + 1);
p[kcs + 1][0] = 0;
}
int main() {
//m关系个数,a,b两者关系
int m, a, b;
cin >> n >> m;
num = n;
while (m--) {
cin >> a >> b;
//存在关系
g[a][b] = g[b][a] = 1;
}
DFS(1, 0);
cout << num << endl;
return 0;
}