一个定义:对一个DAG(无环有向图)进行拓扑排序,是将G中所有顶点排成一个线性序列,使得图中任意一对顶点u和v,若<u,v> ∈E(G),则u在线性序列中出现在v之前。通常,这样的线性序列称为满足拓扑次序(Topological Order)的序列,简称拓扑序列。
1.本题顺序:
a.先判有没有环,有环就直接输出不能确定;(有两种情况,一种是,直接判断反向边,肯定就有环了,第二种情况是,生成的拓扑序内含字母个数小于题目中给出的字母的个数)
b.如果没有环,那么就看会不会有多种情况,如果有多种情况就再读下一行;如果全部行读完还是有多种情况,就是确定不了
c.如果最后没有环,也不存在多种情况(即每次取出来入度为零的点只有一个),那么才是答案
2.有答案就先出答案,不管后面的会不会矛盾什么的
3.如果在没有读完所有输入就能出答案,一定要把剩下的行都读完。
一开始没有往拓扑排序上面想,一开始想的是,找有向图的环。当然,方法很多了。
首先,可以采用如上的拓扑排序。
第二,可以采用寻找SCC(Strongly Connected Component,即强连通分量)的方法来寻找,因为SCC的定义是,u->v, v->u,这正好是环的特征。至于强联通分量,可以采用Tarjan再或者是一个DFS就可以解决,貌似这样慢一些~(还不会写)
第三,可以采用改进的DFS,我们可以对DFS稍加变化,来解决这个问题。解决的方法如下:(更不会写了)
图中的一个节点,根据其C[N]的值,有三种状态:
0,此节点没有被访问过
-1,被访问过至少1次,其后代节点正在被访问中
1,其后代节点都被访问过。
按照这样的假设,当按照DFS进行搜索时,碰到一个节点时有三种可能:
1、如果C[V]=0,这是一个新的节点,不做处理
2、如果C[V]=-1,说明是在访问该节点的后代的过程中访问到该节点本身,则图中有环。
3、如果C[V]=1,类似于2的推导,没有环。 在程序中加上一些特殊的处理,即可以找出图中有几个环,并记录每个环的路径
P.s.:图论毕竟是数学,这才是正常的做题的节奏!
#include <iostream> #include <stack> using namespace std; #define MAXN 27 int graph[MAXN][MAXN], indegree[MAXN], list[MAXN], in[MAXN]; int toposort(int n) { memcpy(in, indegree, sizeof(indegree)); stack<int> s; for (int i = 0; i < n; i++) { if (!in[i])//no indegree (that is to say the indegree of current node is zero) s.push(i); } int countt = 0; bool flag = false; while (!s.empty()) { if (s.size()>1) flag = true;//inconsistency of the separate node, 'cuz there exist multiple ways of toposort. int temp = s.top(); list[countt++] = temp; s.pop(); for (int i = 0; i < n; i++) { if (graph[temp][i] && --in[i] == 0)//if the graph from temp to i is connected and the indegree is still 0 after minus //you may assume that first let's find the component of the graph who is connected from temp to i //then, minus itself by one, check if it's indegree is 0 or not. s.push(i); } } if (countt != n) return 1;//there are a circle in di-graph.(So-called Inconsistency) else if (flag) return 2;//there are multiple solutions return 0;//finally there are solution only. } int main() { int n, m; while (cin >> n >> m && (n || m)) { bool flag = false, flag2 = false; memset(graph, 0, sizeof(graph)); memset(indegree, 0, sizeof(indegree)); for (int i = 1; i <= m; i++) { char a, b, waste; cin >> a >> waste >> b; if (!flag && !flag2) { if (graph[b - 'A'][a - 'A'] == 1)//reverse edge { flag2 = true; cout << "Inconsistency found after " << i << " relations." << endl; continue; } if (graph[a - 'A'][b - 'A'] == 0)//disconnected { graph[a - 'A'][b - 'A'] = 1; indegree[b - 'A']++;//with one indegree of node b } int flag3 = toposort(n); if (flag3 == 0) { cout << "Sorted sequence determined after " << i << " relations: "; for (int j = 0; j < n; j++) cout << (char)(list[j] + 'A'); cout << '.' << endl; flag = true; } else if (flag3 == 1) { cout << "Inconsistency found after " << i << " relations." << endl; flag2 = true; } } } if (!flag && !flag2) cout << "Sorted sequence cannot be determined." << endl; } } |