原题:
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 0Sample Output
Sorted sequence determined after 4 relations: ABCD.
Inconsistency found after 2 relations.
Sorted sequence cannot be determined.Source
East Central North America 2001
翻译:
Description
给定 n 个变量和 m 个不等式。其中 n 小于等于 26,变量分别用前 n 个大写英文字母表示。
不等式之间具有传递性,即若 A>B 且 B>C,则 A>C (2≤n≤26,变量只可能为大写字母 A∼Z)
请从前往后遍历每对关系,每次遍历时判断:
- 如果能够确定全部关系且无矛盾,则结束循环,输出确定的次序;
- 如果发生矛盾,则结束循环,输出有矛盾;
- 如果循环结束时没有发生上述两种情况,则输出无定解。
Input
输入包含多组测试数据。
每组测试数据,第一行包含两个整数 n 和 m。
接下来 m 行,每行包含一个不等式,不等式全部为小于关系。
当输入一行
0 0
时,表示输入终止。Output
每组数据输出一个占一行的结果。
结果可能为下列三种之一:
- 如果可以确定两两之间的关系,则输出
"Sorted sequence determined after t relations: yyy...y."
,其中't'
指迭代次数,'yyy...y'
是指升序排列的所有变量。- 如果有矛盾,则输出:
"Inconsistency found after t relations."
,其中't'
指迭代次数。- 如果没有矛盾,且不能确定两两之间的关系,则输出
"Sorted sequence cannot be determined."
。
具体思路:每读入一个不等式关系后就用Floyd求一次传递闭包,并判断是否矛盾或是否可以确定两两之间的关系,是的话则直接输出结果,否的话则继续以上步骤。
详细部分解析:
Floyd求传递闭包的实现:如果i沿路径可以到达j,则令dist[i][j]=1,否则dist[i][j]=0。在这道题目中,我们将a<b的关系看成a发出一条指向b的边,则dist[a][b]=1。同理,如果b<c,则dist[b][c]=1,既然a<b且b<c,那么a可以沿路径走到c,因此dist[a][c]也等于1。
由上面的推论,我们只需将Floyd求最短路模板中dist[i][j] = min(dist[i][j] , dist[i][k] + dist[k][j])改成dist[i][j] = dist[i][k] && dist[k][j] 即可,即如果i通过k走到j,那么i可以到达j(i<k且k<j那么i<j)
但其实这么写是欠妥的,我们忽略了一种情况:i可以走到j,但是i无法通过k走到j:dist[i][j] = 1,但是dist[i][k]或dist[k][j]中有0的情况,则会将dist[i][j]也置为0,因此正确写法应该为dist[i][j] |= dist[i][k] && dist[k][j]
判断关系是否出现矛盾:如果i<j且j<i则会出现矛盾:i<i ,因此我们可以遍历所有节点,如果出现dist[i][i] = 1则说明出现矛盾情况
判断是否两两之间已确定关系:如果两两之间已经确定关系,对于任意两个顶点i,j必有i < j或j < i即dist[i][j]或dist[j][i]等于1,因此我们只需要判断所有点对是否满足该条件即可
按顺序输出字母:每次只需要输出在未被标记过的字母当中小于其它字母的字母即可,然后标记该字母
代码如下:
#include<bits/stdc++.h>
using namespace std;
#define N 30
int st[N], d[N][N], g[N][N];
int n, m;
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 = i + 1; j < n; j++)
if (!d[i][j] && !d[j][i])return 0;
return 1;
}
char get_min() {
for (int i = 0; i < n; i++) {
int flag = 0;
if (!st[i]) {
for (int j = 0; j < n; j++) {
if (!st[j] && d[j][i]) {
flag = 1;
break;
}
}
if (!flag) {
st[i] = 1;
return 'A' + i;
}
}
}
}
char str[5];
int main(){
int t;//记录轮次
while (cin >> n >> m, n || m) {
memset(g,0,sizeof g);
int type=0;//记录答案类型
for (int i = 1; i <= m; i++) {
cin >> str;
int a = str[0] - 'A', b = str[2] - 'A';
if(!type){
g[a][b] = 1;
floyd();
type=check();
if(type)t=i;
}
}
if (type == 2)printf("Inconsistency found after %d relations.\n", t);
else if (!type)printf("Sorted sequence cannot be determined.\n");
else {
memset(st, 0, sizeof st);
printf("Sorted sequence determined after %d relations: ", t);
for (int i = 0; i < n; i++)
printf("%c", get_min());
printf(".\n");
}
}
return 0;
}
扩展优化: 我们可以尝试将三维缩成两维,在每次添加一个不等式关系a<b后,我们可以做以下操作:1.将“能到达a的点”与“b能到达的点”连接;2.将a与“b能到达的点”连接;3.将“能到达a的点”与b连接。
代码如下:
#include<bits/stdc++.h>
using namespace std;
#define N 30
int st[N], d[N][N];
int n, m;
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 = i + 1; j < n; j++)
if (!d[i][j] && !d[j][i])return 0;
return 1;
}
char get_min() {
for (int i = 0; i < n; i++) {
int flag = 0;
if (!st[i]) {
for (int j = 0; j < n; j++) {
if (!st[j] && d[j][i]) {
flag = 1;
break;
}
}
if (!flag) {
st[i] = 1;
return 'A' + i;
}
}
}
}
char str[5];
int main(){
int t;//记录轮次
while (cin >> n >> m, n || m) {
memset(d,0,sizeof d);
int type=0;//记录答案类型
for (int i = 1; i <= m; i++) {
cin >> str;
int a = str[0] - 'A', b = str[2] - 'A';
if(!type){
d[a][b] = 1;
for(int x=0;x<n;x++){
if(d[x][a])d[x][b]=1;//将能到达a的点与b连接
if(d[b][x])d[a][x]=1;//将a与b能到达的点连接
for(int y=0;y<n;y++)//将能到达a的点与b能到达的点连接
if(d[x][a]&&d[b][y])d[x][y]=1;
}
type=check();
if(type)t=i;
}
}
if (type == 2)printf("Inconsistency found after %d relations.\n", t);
else if (!type)printf("Sorted sequence cannot be determined.\n");
else {
memset(st, 0, sizeof st);
printf("Sorted sequence determined after %d relations: ", t);
for (int i = 0; i < n; i++)
printf("%c", get_min());
printf(".\n");
}
}
return 0;
}