问题描述
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
题解
一开始我的解法是比较单纯(蠢),写了个三重循环,提交之后总是只有60分,最后发现了按照我当时的做法有部分数据是错误的,所以写这个博客给自己加深印象。
错误代码
public class Main {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int n = sc.nextInt(); //学生的人数 即为图的点数
int s = sc.nextInt(); //相认识的对数 即为图的边数
int[][] g = new int[105][105]; //学生关系图
int[] c = new int[105]; //颜色数组
Arrays.fill(c, 0); //颜色数组全部初始化为0
for (int i = 1; i <= s; i++) {
int a = sc.nextInt();
int b = sc.nextInt();
g[a][b] = 1;
g[b][a] = 1;
}for (int i = 1; i <= n; i++) { if (c[i] == 0) { c[i] = 1; } for (int j = 1; j <= n; j++) { if (i == j){ continue; } else if (g[i][j] == 1 && c[j] == 0) { c[j] = 1; for (int z = 1; z <= n; z++) { if (j == z) { continue; } else if (g[j][z] == 1 && c[z] != 0 && c[z] == c[j]) { c[j]++; } } } } } int sum = c[1]; for (int k = 1; k <= n; k++) { System.out.println(c[k] + "and" + k); if (c[k] > sum) { sum = c[k]; } } //System.out.println(sum); }
}
后面找出了一组上面的代码通过不了的数据:
11
7
1 9
2 4
2 6
2 9
5 8
5 10
8 8
后面自己分析了一下,我的错误代码只能满足题目要求的认识的人不在同一个班,但不满足最小数目的要求。 因为我的错误代码的做法是,首先给每一个即将要被安排的学生安排到第一个教室,然后有认识的人就向后移到下一个教室。但是有可能存在这种情况,把即将要被安排的学生直接放到后几个教室(假设前面的教室该学生可以进入)到最后安排的教室的数目更少。
后面查了网上别人的做法,基本上用的都是回溯法,就是可以先试其中一种安排,然后回到原来的状态可以再试另外的安排,找出最少数目的。然后我就自己重新写了一个用这种方法的程序。提交成功。
正确代码
import java.util.*;public class Main {
static int res = 0x3f3f3f; //定义为无穷大
static int n;
static int m;
static int[][] g = new int[110][110];
static int[] c = new int[110];public static boolean judge (int s, int r) { for (int i = 1; i <= n; i++) { if (g[s][i] == 1 && c[i] == r) { return false; } } return true; } public static void F (int s, int r) { //s 代表第几个学生,r代表目前有几个房间 //System.out.println("a"); if (r >= res) { return; } if (s > n) { res = (res>r)?r:res; //取两者中更小的 return; } for (int i = 1; i <= r; i++) { if (judge(s, i)) { c[s] = i; F(s+1, r); c[s] = 0; } } c[s] = r+1; F(s+1, r+1); c[s] = 0; } public static void main(String[] args) { Scanner sc = new Scanner(System.in); n = sc.nextInt(); m = sc.nextInt(); for (int i = 1; i <= m; i++) { int a = sc.nextInt(); int b = sc.nextInt(); g[a][b] = g[b][a] = 1; } F(1, 0); System.out.println(res); }
}
这个代码通过先对其中一种情况进行测试,然后返回将已经安排的学生标记为0再进行测试。其中要记住第一次调用F函数的时候,第二个参数要为0,如果是1的话程序会出现超时的情况。其实这就是一个深度搜索的问题,通过画树状图可以更好的理解这个程序。