问题描述
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
这应该是一道图的着色的题目
我最开始觉得应该是这么做的:
设d(S)表示把结点集S染色,所需要颜色数的最小值,则d(S)=d(S-S’)+1,其中S’是S的子集,并且内部没有边(即不存在S’内的两个结点u和v使得u和v相邻)。换句话说,S’是一个“可以染成同一种颜色”的结点集
——来自《算法竞赛入门经典(第二版)》P286
但是发现2^100这是什么神仙数字???所以只能用回溯法做了
#include<cstdio>
#include<algorithm>
using namespace std;
const int MAXN = 105;
int frien[MAXN][MAXN], room[MAXN], n, m, ans = 100; // frien[i][0]存储第i个人有多少个朋友
bool hasFrien[MAXN];
void read () {
scanf("%d\n%d", &n, &m);
for (int i = 0, a, b; i < m; i++) {
scanf("%d %d", &a, &b);
if (a > b) {
frien[a][0]++;
frien[a][frien[a][0]] = b;
} else {
frien[b][0]++;
frien[b][frien[b][0]] = a;
}
}
}
void dfs (int cur, int cnt) {
if (cur == n+1) {
ans = min(ans, cnt);
} else {
if (cnt >= ans) return; // 剪枝,现在的教室已经大于等于最多的教室了,在怎么安排都不能是答案
// 查看那些教室可以被放人
for (int i = 1; i <= cnt; i++) {
hasFrien[i] = false;
}
for (int i = 1; i <= frien[cur][0]; i++) {
hasFrien[room[frien[cur][i]]] = true;
}
// 安排一间旧教室
for (int i = 1; i <= cnt; i++) {
if (!hasFrien[i]) {
// 安排一间旧教室
room[cur] = i;
dfs(cur+1, cnt);
room[cur] = 0;
}
}
// 安排一间新教室
room[cur] = cnt+1;
dfs(cur+1, cnt+1);
room[cur] = 0;
}
}
int main () {
read();
dfs(1, 1);
printf("%d", ans);
return 0;
}
其实我有一个疑惑,那么在图的染色的问题时,位压dp什么时候有用呢?