拓扑排序,就是按这个顺序遍历图时,这个图不会出现一个点v的入边的另一个出发点没被遍历过.
就像这张图的一个top序:
比如:4 1 3 2 5
不过一般我们是求字典序最小的:1 4 3 2 5
实现的思路就是不断刷点,先入度为0的点刷掉,上推中是刷掉1和4.
然后将所有以这些点为出发点的边去掉,成为一张新的图重复刷点.
然后就是top序了.
具体的实现就是一个计数器加上一个bfs遍历.
注:有环图语无向图不存在top序.
代码如下:
inline void topsort(){ head=0;tail=0; for (int i=1;i<=n;i++) if (!coun[i]) q[++tail]=i; while (head<=tail){ ++head; for (int i=lin[q[head]];i;i=e[i].next){ int j=e[i].y; coun[j]--; if (!coun[j]) q[++tail]=j; } top[++topt]=q[head]; } }
注:其实q队列存档就是top序,这样可以省一个数组.
对了还有个判环条件:若执行完了循环还有coun[i]不为0说明有环.
至于怎么输出字典序最小,就改用优先队列.
代码如下:
inline void topsort(){ for (int i=1;i<=n;i++) if (!coun[i]) q.push(i); while (!q.empty()){ int u=q.top(); q.pop(); top[++topt]=u; for (int i=lin[u];i;i=e[i].next){ int j=e[i].y; coun[j]--; if (!coun[j]) q.push(j); } } }
注意,q.pop()和u=q.top()一定要在前面写,一定不能写在后面.
不然的话会把新填进来的j给掺进来.
但是由于不用字典序最小时,队头不会改变,所以第一串代码可以写在后面.