POJ1094(拓扑排序)
Sorting It All Out
Description
An ascending sorted sequence of distinct values is one in which some form of a less-than operator is used to order the elements from smallest to largest. For example, the sorted sequence A, B, C, D implies that A < B, B < C and C < D. in this problem, we will give you a set of relations of the form A < B and ask you to determine whether a sorted order has been specified or not.
Input
Input consists of multiple problem instances. Each instance starts with a line containing two positive integers n and m. the first value indicated the number of objects to sort, where 2 <= n <= 26. The objects to be sorted will be the first n characters of the uppercase alphabet. The second value m indicates the number of relations of the form A < B which will be given in this problem instance. Next will be m lines, each containing one such relation consisting of three characters: an uppercase letter, the character “<” and a second uppercase letter. No letter will be outside the range of the first n letters of the alphabet. Values of n = m = 0 indicate end of input.
Output
For each problem instance, output consists of one line. This line should be one of the following three:
Sorted sequence determined after xxx relations: yyy…y.
Sorted sequence cannot be determined.
Inconsistency found after xxx relations.
where xxx is the number of relations processed at the time either a sorted sequence is determined or an inconsistency is found, whichever comes first, and yyy…y is the sorted, ascending sequence.
Sample Input
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
Sample Output
Sorted sequence determined after 4 relations: ABCD.
Inconsistency found after 2 relations.
Sorted sequence cannot be determined.
题意
有 1 ~ N 个大写字母,且从 A 开始依次 N 个。再给你 M 个小于的关系,比如 A < B ,让你判断三种可能:
1、在第 i 个关系罗列之后,是否可以满足使得这 N 个字母能递增关系。
2、在第 i 个罗列之后,是否会出现矛盾,例如 A > B,而在第 i 个状态出现后,B > A ,故矛盾。
3、如果 M 个条件罗列完后都没有出现矛盾,且还无法判断 N 个字母的排列顺序,则输出 Sorted sequence cannot be determined.
思路
对于 A < B,我们建一个 A --> B 的有向图。
每输入一条关系,进行一次拓扑排序:
- 如果某一次拓扑之后发现存在环路,结束并输出"Inconsistency found after 2 relations."(其中2为第几步)。
- 如果在拓扑排序过程中,某一次判断存在入度为0的点不止一个,跳过此次拓扑排序,输入下一条关系。
- 如果所有关系输入完成,拓扑序列不唯一确定。输出"Sorted sequence cannot be determined."。
- 如果在第i关系之后,拓扑排序已经唯一确定,输出"Sorted sequence determined after i relations: ABCD."(ABCD为最终的拓扑排序)
注意:当序列有多种拓扑顺序且还有环存在时,输出的结果应该为有环存在的情况。所以每次拓扑排序都需要完整的做完,而不是当有多个入度为0的顶点的时候就返回。
代码
package _topologicalSort.problem1094;
import java.util.Scanner;
public class SortingItAllOut {
public static int max = Integer.MAX_VALUE;
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
SortingItAllOut sortingItAllOut = new SortingItAllOut();
while (true) {
int n = sc.nextInt();//字母个数
int m = sc.nextInt();//关系数量
if (m == 0 && n == 0) {
break;
}
int[][] graph = new int[n][n];
char[] nodes = new char[n];
for (int i = 0; i < n; i++) {//初始化图
nodes[i] = (char) (65 + i);//大写字母A到ASCII为65
for (int j = 0; j < n; j++) {
if (i == j) {
graph[i][j] = 0;
} else {
graph[i][j] = max;
}
}
}
int step = 0;
String result = "";
boolean flag = false;
for (int i = 0; i < m; i++) {
String str = sc.next();
if (flag) {//已经唯一确定或已经存在环路
continue;
}
step++;
char from;
char to;
if (str.charAt(1) == 60) {//小于号的ASCII为60,输入一条关系,判断这条关系的起点和终点
from = str.charAt(0);
to = str.charAt(2);
} else {
from = str.charAt(2);
to = str.charAt(0);
}
graph[from - 65][to - 65] = 1;//将这条关系更新到图中,大写字母A到ASCII为65
result = sortingItAllOut.topologicalSort(graph, nodes);
if (result.equals("ring")) {//存在环路
System.out.println("Inconsistency found after " + step + " relations.");
flag = true;
} else if (!result.equals("notUnique")) {//唯一确定排序
System.out.println("Sorted sequence determined after " + step + " relations: " + result + ".");
flag = true;
}
}
if (result.equals("notUnique")) {
System.out.println("Sorted sequence cannot be determined.");
}
}
}
public String topologicalSort(int[][] graph1, char[] nodes) {
int[][] graph = new int[graph1.length][graph1.length];
for (int i = 0; i < graph.length; i++) {
for (int j = 0; j < graph.length; j++) {
graph[j][i] = graph1[j][i];
}
}
String result = "";
int[] nums = new int[graph.length];//记录顶点的入度
boolean flag = true;
boolean notUnique = false;//是否唯一
boolean ring = false;//是否存在环路
while (flag) {
flag = false;
for (int i = 0; i < graph.length; i++) {//统计每个顶点的入度
if (nums[i] == -1) {//此顶点已经输出过
continue;
}
int num = 0;
for (int j = 0; j < graph.length; j++) {
if (graph[j][i] != 0 && graph[j][i] != max) {
num++;
}
}
nums[i] = num;
}
int count = 0;//入度为0的点到个数
int index = -1;//入度为0的点的下标
for (int i = 0; i < nums.length; i++) {
if (nums[i] == 0) {//如果某个顶点的入度为0。
count++;
index = i;
}
}
if (count > 0) {//存在入度为0的点
result = result + nodes[index];
nums[index] = -1;
for (int j = 0; j < graph.length; j++) {//删除所有以该点为起点的边
graph[index][j] = max;
}
flag = true;
}
if (count > 1) {//入度为0的点不止1个
notUnique = true;//拓扑排序不唯一
}
}
for (int i = 0; i < nums.length; i++) {
if (nums[i] != -1) {//有点没有输出,存在回路
ring = true;
}
}
if (ring) {//存在环路
result = "ring";
} else if (notUnique) {
result = "notUnique";
}
return result;
}
}