问题描述
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.youkuaiyun.com/habewow/article/details/80410177
package com.xjj.lanqiao;
import java.util.LinkedList;
import java.util.List;
import java.util.Scanner;
/**
* @author XJJ
* 回溯法--类似地图着色问题
*/
public class Lq5_53 {
static int n, result;
static boolean[][] book;
static List<List<Integer>> list = new LinkedList<>();
public static void dfs(int step) {
if (step == n+1) { // 选最少优
result = Math.min(result, list.size());
return;
}
// 剪枝,当当前的大于之前找到的,则不需再找
if (list.size() > result) {
return;
}
// 在已经有的集合里遍历每一个元素
for(int i = 0; i < list.size(); i++) {
// 从0开始与下面notFriend对应
if (notFriend(i, step)) {
list.get(i).add(step);
dfs(step+1);
// 回溯,将刚才加入的元素移出
list.get(i).remove(list.get(i).size()-1);
}
}
// 为了新开集合
List<Integer> temp = new LinkedList<>();
temp.add(step);
list.add(temp);
dfs(step+1);
// 回溯,将刚才加入的元素移出
list.remove(list.size()-1);
}
// 判断当前两人是否认识
public static boolean notFriend(int index, int now) {
for(int i = 0; i < list.get(index).size(); i++) {
if (book[now][list.get(index).get(i)]) {
return false;
}
}
return true;
}
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
n = scanner.nextInt(); // 人数
int m = scanner.nextInt(); // 行数
book = new boolean[n+1][n+1];
for(int i = 0; i < m; i++) {
int a = scanner.nextInt();
int b = scanner.nextInt();
book[a][b] = book[b][a] = true;
}
result = Integer.MAX_VALUE;
dfs(1);
System.out.println(result);
}
}