传送门:http://poj.org/problem?id=1094
这题就是普通的拓扑排序,但是有几个要点要注意
首先就是要记录在输入到哪一步的时候会产生什么样的结果,如果产生了答案或者产生了环就略过接下来的输入。
为了达到这样的效果,只能输入一条边就拓扑一次,看看有没有产生答案。
我因为判断结果的优先级搞错了wa了很多次
产生了答案或者产生环的优先级都是高于不能排序的。也就是说,即使没有产生答案,但是有环的话,也是直接输出有环。
代码如下
#include<cstdio>
#include<string>
#include<vector>
#include<cmath>
#include<set>
#include<cstdlib>
#include<algorithm>
#include<queue>
#include<map>
#include<cstring>
#include<iostream>
using namespace std;
int n, m;
int ind[30];
int temp[30];
bool vis[30];
char seq[30];
vector < vector<int> > v;
int topsort(int now)
{
int q = now;
int i, j;
for (i = 0; i < n; i++) temp[i] = ind[i];
int len = 0, cot = 0;
bool ok = true;
int del = 0;//记录在拓扑的时候删除了几个点
while (now--)
{
cot = 0;//记录入度为0的点有几个
for (i = 0; i < n; i++)
{
if (temp[i] == 0)
{
j = i;
cot++;
}
}
if (cot >= 1)
{
if (cot > 1)//即使此时有多种结果,也要删点。为了判断有没有环,拓扑还是要做完才能return
ok = false;
for (i = 0; i < v[j].size(); i++)
temp[v[j][i]]--;
temp[j] = -1;
del++;
seq[len++] = j + 'A';
seq[len] = '\0';
}
else if (cot == 0)//此时肯定有环,直接return
return -1;
}
if (ok)
return 1;
else if (del != q)//q为当前图中存在的点数
return -1;
return 0;
}
int main()
{
// freopen("D://input.txt", "r", stdin);
while (scanf("%d%d", &n, &m) != EOF&&n&&m)
{
memset(ind, 0, sizeof(ind));
memset(vis, false, sizeof(vis));
v.clear(); v.resize(n);
int ans = 0;
int i;
char s[5];
int a, b;
int ok = 0, cot = 0;//cot记录当前图中存在的点
for (i = 0; i < m; i++)
{
scanf("%s", s);
if (ok != 0)
continue;
a = s[0] - 'A';
b = s[2] - 'A';
ind[b]++;
v[a].push_back(b);
if (!vis[a]) {
vis[a] = true;
cot++;
}
if (!vis[b]) {
vis[b] = true;
cot++;
}
ok = topsort(cot);
if (ok != 0)
ans = i + 1;//ans记录几回合产生答案的
}
if (ok == 1) {
printf("Sorted sequence determined after %d relations: %s.\n", ans, seq);
}
else if (ok == 0) {
printf("Sorted sequence cannot be determined.\n");
}
else {
printf("Inconsistency found after %d relations.\n", ans);
}
}
return 0;
}