有向图的top排序——图上DP的基础

拓扑排序,就是按这个顺序遍历图时,这个图不会出现一个点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给掺进来.

但是由于不用字典序最小时,队头不会改变,所以第一串代码可以写在后面.

猜你喜欢

转载自blog.csdn.net/hzk_cpp/article/details/79731716