题目链接:Acwing_343排序
思路分析:
-
本题考察Floyd算法在传递闭包问题上的应用。给定若干对元素和若干对二元关系,并且关系具有传递性,通过传递性推导出尽量多的元素之间的关系的问题被称为传递闭包。比如a < b,b < c,就可以推导出a < c,如果用图形表示出这种大小关系,就是a到b有一条有向边,b到c有一条有向边,可以推出a可以到达c,找出图中各点能够到达点的集合,就类似于Floyd算法求图中任意两点间的最短距离。Floyd求解传递闭包问题的代码如下:
-
只是对原来算法在状态转移方程上略加修改 就能够求解传递闭包问题了。f[i][j] = 1表示i可以到达j ( i < j),f[i][j] = 0表示i不可到达j。只要i能够到达k并且k能够到达j,那么i就能够到达j,这就是上面代码的含义。
-
对于本题而言,给定n个元素和一堆二元关系,依次读取每个二元关系,在读取第i个二元关系后,如果可以确定n个元素两两间的大小关系了,就输出在几对二元关系后可以确定次序,并且次序是什么;如果出现了矛盾,就是A < B并且B < A这种情况发生了就输出多少对二元关系后开始出现矛盾;如果遍历完所有的二元关系还不能确定所有元素间的大小关系,就输出无法确定。
-
可以发现,题目描述要求按顺序遍历二元关系,一旦前i个二元关系可以确定次序了就不再遍历了,即使第i + 1对二元关系就会出现矛盾也不去管它了。对于二元关系的处理和之前的做法一样,A < B,就将f[0][1]设为1,题目字母只会在A到Z间,因此可以映射为0到25这26个元素,如果f[0][1] = f[1][0] = 1,就可以推出f[0][0] = 1,此时A < B并且A > B发生矛盾,因此在f[i][i]= 1时发生矛盾。
AC代码:
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
const int N = 26;
int n, m;
bool g[N][N], d[N][N];
bool st[N];
void floyd() {
memcpy(d, g, sizeof d);
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++)
{
if (!st[j] && d[j][i])
{
flag = false;
break;
}
}
if (flag)
{
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';
if (!type)
{
g[a][b] = 1;
floyd();
type = check();
if (type) t = i;
}
}
if (!type) puts("Sorted sequence cannot be determined.");
else if (type == 2) printf("Inconsistency found after %d relations.\n", t);
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");
}
}
system("pause");
return 0;
}