问题描述
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
代码:
import java.util.*;
public class Main {
//判断两人是否认识
static boolean flag[][];
static int n,ans;
//存放教室
static List<List<Integer>>list=new LinkedList<List<Integer>>();
public static void main(String[] args) {
Scanner scanner=new Scanner(System.in);
//人数
n=scanner.nextInt();
//组数
int m=scanner.nextInt();
//00代表初始的喔,下标从1开始,故n+1
flag=new boolean[n+1][n+1];
for(int i=0;i<m;i++){
int a=scanner.nextInt();
int b=scanner.nextInt();
flag[a][b]=flag[b][a]=true;
}
//分考场的总数
ans=101;
dfs(1);
System.out.println(ans);
}
/**
* 通过flag判断当前的now是否与当前教室中的人认识,是否可以放到当前的list中去
* @param index 教室的编号
* @param now 当前要加入交是的同学编号
* @return
*/
static boolean check(int index,int now){
//list.get(index).size()得到教室的人数
for(int i=0;i<list.get(index).size();i++){
//list.get(index).get(i)代表该教室的第i个学生的编号
if(flag[now][list.get(index).get(i)]){
return false;
}
}
return true;
}
public static void dfs(int now){
if(now==n+1){//当前的学生编号大于总人数,则选优
//选优,list.size()为当前教室的总数
ans=Math.min(ans,list.size());
return;
}
//当你这个状态的递归得到的教室数目已经大于已知状态的教室数目,则退出
if(list.size()>=ans) return;
//依次的遍历第i个教室的学生,查看是否认识now
for(int i=0;i<list.size();i++){
if(check(i, now)){//不认识now
//把当前学生加入该教室
list.get(i).add(now);
//递归下一个学生
dfs(now+1);
//回溯,删除刚刚加进去的那个人
list.get(i).remove(list.get(i).size()-1);
}
}
//以下当now都被所有所有教室的学生认识或者就算不认识也不加入已知的教室,则新建一个教室存放now
//创建临时的list,即教室
List<Integer>temp=new LinkedList<>();
//该教室加入当前的那个学生
temp.add(now);
//登记该教室
list.add(temp);
//递归这种情况
dfs(now+1);
//回溯,将刚才加入的教室删除,表示这种状态递归搜索完成,初始化list以备下次递归
list.remove(list.size()-1);
}
}
参考博客: