题目描述:
给定 n 个变量和 m 个不等式。其中 n 小于等于 26,变量分别用前 n 的大写英文字母表示。
不等式之间具有传递性,即若 A>B 且 B>C,则 A>C。
请从前往后遍历每对关系,每次遍历时判断:
- 如果能够确定全部关系且无矛盾,则结束循环,输出确定的次序;
- 如果发生矛盾,则结束循环,输出有矛盾;
- 如果循环结束时没有发生上述两种情况,则输出无定解。
输入格式
输入包含多组测试数据。
每组测试数据,第一行包含两个整数 n 和 m。
接下来 m 行,每行包含一个不等式,不等式全部为小于关系。
当输入一行 0 0 时,表示输入终止。
输出格式
每组数据输出一个占一行的结果。
结果可能为下列三种之一:
- 如果可以确定两两之间的关系,则输出 “Sorted sequence determined after t relations: yyy…y.”,其中’t’指迭代次数,'yyy…y’是指升序排列的所有变量。
- 如果有矛盾,则输出: “Inconsistency found after t relations.”,其中’t’指迭代次数。
- 如果没有矛盾,且不能确定两两之间的关系,则输出 “Sorted sequence cannot be determined.”。
数据范围
2≤n≤26,变量只可能为大写字母 A∼Z。
输入样例1:
4 6
A<B
A<C
B<C
C<D
B<D
A<B
3 2
A<B
B<A
26 1
A<Z
0 0
输出样例1:
Sorted sequence determined after 4 relations: ABCD.
Inconsistencyfound after 2 relations.
Sorted sequence cannot be determined.
输入样例2:
6 6
A<F
B<D
C<E
F<D
D<E
E<F
0 0
输出样例2:
Inconsistency found after 6 relations.
题目链接:排序
分析:
- 根据传递闭包的性质,去推出每个元素之间的大小关系,例如A<B, B<C就可以推出A<C,每加入一对关系,就要去更新所有元素之间的关系,这就可以使用Floyd算法去解决。
- 每更新一次元素间的关系,就去判断是否有矛盾,有矛盾就不用再去Floyd了,输出添加几次关系之后得到的矛盾。若添加完所有关系后没有矛盾,则又有两种情况:
a.不能确定所有元素两两之间的关系:某个元素跟其他任意一个或多个元素没有大小关系
b.不满足a则满足b。任意一个元素都跟其他所有元素能确定大小关系
注意:a和b都是在任意元素之间没有矛盾的前提下的
代码(含注释):
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.util.Arrays;
public class Main {
static boolean[][] d = new boolean[26][26];//d[i][j]为true表示i < j
static boolean[] st = new boolean[26]; //用来后面输出元素顺序
static int n, m; //n个元素,m条关系
public static void main(String[] args) throws Exception{
//采用快读的方式
BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
String[] tmp = reader.readLine().split(" ");//tmp数组用来判断是否读到”0 0“
while(!tmp[0].equals("0")) {
for (int i = 0; i < 26; i++) //可能有多组数据
Arrays.fill(d[i], false);//所以每执行完一段就要重置d数组
n = Integer.parseInt(tmp[0]); m = Integer.parseInt(tmp[1]);
int type = 0, step = 0; //type用来记录它的结果是哪一种,step记录推导次数
for (int i = 1; i <= m; i++) {
char[] c = reader.readLine().toCharArray();
int a = c[0]-'A', b = c[2]-'A';
if (type==0) { //此处type为0表示暂时不能确定关系
d[a][b] = true; //a<b为真
floyd(); //更新所有元素关系
type = check(); //每更新一次关系就去检查是否存在矛盾
if (type!=0) step = i; //更新推导次数
}
}
if (type==0) //此处若type仍为0,则表示不能确定
System.out.println("Sorted sequence cannot be determined.");
else if (type==1) //为1表示有矛盾
System.out.println("Inconsistency found after "+step+" relations.");
else { //为2表示能确定关系
Arrays.fill(st, false); //因为可能有多组数据,所有st数组也需要重置
System.out.print("Sorted sequence determined after "+step+ " relations: ");
for (int i=0;i<n;i++)
System.out.print(getMin()); //每次输出所有关系中最小的
System.out.println('.');
}
tmp = reader.readLine().split(" ");//读取下一行数据
}
}
public static void floyd() { //Floyd更新两点间关系
for (int k = 0; k < n; k++)
for (int i = 0; i < n; i++)
for (int j = 0; j < n; j++) {
d[i][j] |= d[i][k]&&d[k][j];
}
}
public static int check() {
for (int i = 0; i < n; i++) //若能推出i<i,则返回1表示有矛盾
if (d[i][i]) return 1;
for (int i = 0; i < n; i++)
for (int j = 0; j < n; j++) //若没有矛盾,但有不能确定的点
if (i!=j&&!d[i][j]&&!d[j][i]) //返回0表示暂时不能确定
return 0;
return 2; //上面两个都不满足则表示能确定关系,返回2
}
public static char getMin() { //获取最小的元素
for (int i = 0; i < n; i++) {
if (!st[i]) {
boolean flag = true;
for (int j = 0; j < d.length; j++) {
if (!st[j]&&d[j][i]) { //若没访问过,但有其他点比他小,就跳过
flag = false;
break;
}
}
if (flag) { //若上面for循环走完flag仍为1,则表示它就是最小的
st[i] = true;
return (char) (i+'A');
}
}
}
return ' '; //因为一定有解,所以这里不会执行,只是为了解决编译报错
}
}