标题:分考场
题目
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迭代考虑, 然后贪心的将第S个学生加入到已开设的房间, 若不行则开设新房间
代码
package ex1.extest;
import java.util.ArrayList;
import java.util.List;
import java.util.Scanner;
public class a04dfs {
static int n,m,num=0,min=140;
static boolean[][] arr; // 存储学生关系
static int[][] con;
// con con[i][0] 表示第i个房间的学生数,
// cin[i][j] j>0 表示第i个房间的一个学生编号为j
public static void main(String[] args){
Scanner scanner = new Scanner(System.in);
n = scanner.nextInt();
m = scanner.nextInt();
arr = new boolean[105][105];
con = new int[105][105];
for (int i=0; i<m; i++) {
int a = scanner.nextInt();
int b = scanner.nextInt();
arr[a][b]=true;
arr[b][a]=true;
}
dfs(1); // 当前学生
System.out.println(min);
}
public static void dfs(int s) { // 考虑的第S个学生
if (num>min)return; // 剪枝 num 表示当前方案所需要的房间数,
if (s>n){
min = min>num ? num : min;
return;
}
boolean flag=false;
for (int i=1; i<=num; i++) {// 遍历当前已分配的房间,贪心的加入到已分配的房间
flag=false;
for (int j=1; j<=con[i][0]; j++) {
int x = con[i][j];
if (arr[x][s]) {
flag=true;
break;
}
}
if (!flag) {// 如果可以加到i
int ax = ++con[i][0];
con[i][ax]= s;
dfs(s+1);
con[i][0]--;
}
}
// 开设一个新房间
num++;
con[num][++con[num][0]] = s;
dfs(s+1);
con[num][0]--;
num--;
}
}
肝完, 其实dfs深度遍历在暴力破解中很常用,要注意剪枝,回溯,贪心结合使用
如果dfs的每一条线路用的是同一个数据(数组或者链表)则一定要加回溯
剪枝和贪心用的好可以大大提高效率
若需要测试数据,评论区回复即可