题目链接:http://poj.org/problem?id=1094
思路:因为要找第一个满足拓扑排序的或是有环的,所以要从第一个输入就开始判断。这里要注意一点,如果判断时发现有环了,那么后面都不用管了,答案就是有环;如果判断时发现满足拓扑排序了,那么后面也不用管了(不管后面有没有和前面形成环),答案就是满足拓扑。
先判断环,再判断拓扑排序比较方便。判环时,可以用DFS,方法如下,令vis[i] == 0表示结点i还没被访问、vis[i] == -1表示结点正在访问、vis[i] == 1表示节点已访问完成,如果在访问的过程中发现某个子结点的vis为-1,则存在环。若结点i访问完成并且没有环,则令vis[i] == 1,后面再扫到v时直接跳过即可(因为i点不在环中)。
判断完环后,再判断拓扑排序就简单了(这里的拓扑排序是必须满足任意两点都可比较)。从图中找入度为0的结点,若个数大于1,则不满足,否则删除该点即该点所连的边,继续重复前面的过程,直到所有点被删光为止。
#include<cstdio>
#include<cstring>
#include<string>
#include<cctype>
#include<iostream>
#include<set>
#include<map>
#include<cmath>
#include<sstream>
#include<vector>
#include<stack>
#include<queue>
#include<bitset>
#include<algorithm>
#define fin() freopen("A.txt","r",stdin)
#define fout() freopen("B.txt","w",stdout)
typedef long long ll;
using namespace std;
const int maxn = 30;
string ans;
vector<int> G[maxn];
int vis[maxn];
int degree[maxn];
int n, m;
bool dfs(int u) {
if(vis[u] == -1) return false;
vis[u] = -1;
for(int i = 0; i < G[u].size(); i++) {
int v = G[u][i];
if(vis[v] == 1) continue;
if(!dfs(v)) return false;
}
vis[u] = 1;
return true;
}
bool is_circle() {
memset(vis, 0, sizeof vis);
for(int i = 0; i < n; i++) if(!vis[i]){
if(!dfs(i)) return true;
}
return false;
}
bool is_topo() {
string s;
int ru[maxn];
memset(vis, 0, sizeof vis);
for(int i = 0; i < n; i++) ru[i] = degree[i];
bool ok = true;
for(;;) {
int cnt = 0, temp = 0;
for(int i = 0; i < n; i++) {
if(!ru[i] && !vis[i]) {
cnt++; vis[i] = 1; temp = i;
}
}
if(cnt != 1) {
if(cnt > 1) ok = false;
break;
}
s += (char)(temp+'A');
for(int i = 0; i < G[temp].size(); i++) {
int v = G[temp][i];
ru[v]--;
}
}
if(ok) ans = s;
return ok;
}
int main() {
while(scanf("%d%d", &n, &m) && n) {
memset(degree, 0, sizeof degree);
for(int i = 0; i < n; i++) G[i].clear();
int circle = 0, topo = 0;
for(int i = 1; i <= m; i++) {
char s[5]; scanf("%s" ,s);
if(circle || topo) continue;
int u = s[0] - 'A', v = s[2] - 'A';
degree[v]++;
G[u].push_back(v);
if(is_circle()) circle = i;
if(!circle && !topo && is_topo()) topo = i;
}
if(circle) printf("Inconsistency found after %d relations.\n", circle);
else if(topo) printf("Sorted sequence determined after %d relations: %s.\n", topo, ans.c_str());
else printf("Sorted sequence cannot be determined.\n");
}
return 0;
}