给定 n 个变量和 m 个不等式。其中 n 小于等于 26,变量分别用前 n 的大写英文字母表示。
不等式之间具有传递性,即若 A>B 且 B>C,则 A>C。
请从前往后遍历每对关系,每次遍历时判断:
- 如果能够确定全部关系且无矛盾,则结束循环,输出确定的次序;
- 如果发生矛盾,则结束循环,输出有矛盾;
- 如果循环结束时没有发生上述两种情况,则输出无定解。
输入格式
输入包含多组测试数据。
每组测试数据,第一行包含两个整数 n 和 m。
接下来 m 行,每行包含一个不等式,不等式全部为小于关系。
当输入一行
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. Inconsistency found 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.
输入样例3:
5 5 A<B B<C C<D D<E E<A 0 0
输出样例3:
Sorted sequence determined after 4 relations: ABCDE.
这题时典型得传递闭包问题:
传递闭包:若i到k有条边且k到j有条边则从i到j连一条边如何求传递闭包?
假设一个数组g[i][j]若g[i][j] == 1说明从i到j有一条边,若g[i][j] == 0说明没有边
数组d为传递闭包
则对g[i][j]求一便floyd算法即为传递闭包
void floyd() { memcpy(d, g, sizeof g); 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]; }
为何时|=不是==??
因为只要在之前有一条从i到j的边则说明从i到j存在边
为何是&??
因为只有当i能走到k且k能走到j两个同时满足则说明能从i到j;
所以d[i][j] == 1说明从i到j有一条边,若d[i][j] == 0说明从i到j没有边
因此可分为三种情况:
1:若d[i][i] == 1说明无解:(假设其中有一点k,则表示从i到k有边且从k到i有边即i < i && i > i)
2:若!d[i][j] && !d[j][i]说明关系未确定;(说明从i到j没有边则说明不确定)
3:否则说明关系唯一确定从小到大输出字典序
如何按照字典序输出?
从小到大遍历每个字母,若不存在比它小的则直接输出
char get_min()//按从小到大字典序输出 { for (int i = 0; i < n; i ++ ) { if (!st[i]) { bool flag = true; for (int j = 0; j < n; j ++ )//若j在之前还未输出过且j比i小 if (!st[j] && d[j][i]) { flag = false; break; } if (flag) //若不存在比i小的,则说明i即为最小的 { st[i] = true; return 'A' + i; } } } }
整体代码如下:
#include <cstdio> #include <cstring> #include <iostream> using namespace std; const int N = 30; int n, m; bool st[N]; int d[N][N]; int g[N][N]; void floyd() { memcpy(d, g, sizeof g); 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]; } int check() { for (int i = 0; i < n; i ++ )//说明无解: if (d[i][i]) return 2; for (int i = 0; i < n; i ++ ) for (int j = 0; j < i; j ++ ) if (!d[i][j] && !d[j][i])//说明不确定 return 0; return 1;//说明唯一确定 } char get_min()//按从小到大字典序输出 { for (int i = 0; i < n; i ++ ) { if (!st[i]) { bool flag = true; for (int j = 0; j < n; j ++ )//若j在之前还未输出过且j比i小 if (!st[j] && d[j][i]) { flag = false; break; } if (flag) //若不存在比i小的,则说明i即为最小的 { st[i] = true; return 'A' + i; } } } } int main() { while (cin >> n >> m, n || m) { memset(g, 0, sizeof g); int type = 0, t; for (int i = 1; i <= m; i ++ ) { char str[5]; cin >> str; int a = str[0] - 'A', b = str[2] - 'A';//将A - Z映射成0 -> 25 if (!type)//type == 0说明不确定, type == 1说明唯一确定, type == 2说明有矛盾 { g[a][b] = 1;//a < b从a -> b连一条边 floyd();//求传递闭包 type = check();//检查是什么类型 if (type) t = i;//即使能确定也不能break要全部读完防止上一轮数据影响 } } if (type == 2) printf("Inconsistency found after %d relations.\n", t); else if (type == 0) printf("Sorted sequence cannot be determined.\n"); else { printf("Sorted sequence determined after %d relations: ", t); memset(st, 0, sizeof st);//先清空以免上一轮产生影响 for (int i = 0; i < n; i ++ ) printf("%c", get_min()); printf(".\n"); } } return 0; }