拓扑排序

拓扑排序

可以用来检查有没有拓扑序 以及有没有环存在,环中的元素有哪些,以及题目出现又依赖关系 以及图的问题中出现了要从某个特定度的节点开始往里面剥的情况 ,就考虑top操作
关于模板的使用问题:

  • 进过队列中的元素是可以被拓扑排序删去的节点(有拓扑序的元素) ,也是不属于环中节点的节点,进过队列的元素按顺序就是拓扑序,没有进队列的元素就是环中的节点。
  • 所以如果有n个元素入队了 说明有拓扑序,不然没有,注意手写队列是从0开始,所以遍历结束条件是i < n ,也可以是i <= tt.
#include <iostream>
#include <algorithm>
#include <cstring>
using namespace std;

const int N = 100010,M = N;
int n , m;
int h[N],e[M],ne[M],idx;
int q[N],hh,tt = -1;
int d[N];

void add(int a,int b){
    e[idx] = b,ne[idx] = h[a],h[a] = idx ++ ;
}


int topsort(){
    for(int i = 1;i <= n;i ++) if(!d[i]) q[++ tt] = i;
    
    while(hh <= tt) {
        int t = q[hh ++];
        
        for(int i = h[t];i != -1;i = ne[i]) {
            int j = e[i];
            d[j] -- ;
            if(!d[j]) q[++ tt] = j; 
        }
    }
    if(tt + 1 < n) return  -1;//如果有n个元素入队了 说明有拓扑序,不然没有
    else return 0;
}

int main(){
    cin >> n >> m;
    memset(d,0,sizeof d);
    memset(h,-1,sizeof h);
    for(int i = 0 ;i < m;i ++) {
        int a,b;
        cin >> a >> b ;
        add(a,b);
        d[b] ++ ;
    }
    
    
    int t =  topsort();
    if(t == -1) cout << -1;
    else {
        for(int i = 0 ;i < n;i ++) {
            cout << q[i] << " " ;//队列中的元素就是拓扑序,就i是可以被拓扑排序删去的节点 ,也是不属于环中节点的节点
        }
    }
    return 0;
}

课程表专题

1.手写队列的使用问题 ,是tt + 1 < n,第一个数在队列里是存在0的位置 ,然后再最后输出的时候这个i < n 如果是换成tt 就是i <= tt

找到最终的安全状态
1.反向建图,问环中的元素是什么 所以可以使用拓扑排序
2.模板的使用,进过队列的元素就是具有拓扑序的元素,没有进去的就是环中的元素

310.最小高度树
1.拓扑排序的变形,叶子节点开始往里一层一层剥开,然后最后一层就是最小高度树的根节点
2.用一个res来打雷存最后的答案
3.拓扑排序的第二个模板,看背诵的题
4.图的情况下求树的深度的 对叶子节点base case的处理,用一个leaf标记看看是不是有他又叶子节点。

posted @ 2020-12-16 14:36  驿站Eventually  阅读(90)  评论(0编辑  收藏  举报