算法题--拓扑排序

拓扑排序

  对一个有向无环图进行拓扑排序,所谓的拓扑排序就是将一系列事件按照一定的顺序进行排列,要求是在前面的事件是后面事件的先决条件,也就是说,要想进行后面的事件,必须要将该事件前面全部的先决条件完成才可以进行该事件,在有向无环图中体现某事件是另一个事件的先决条件的是,每条边的起点是它的终点的先决条件。

典型例题:

1 有向图的拓扑序列

题意给定一个n个点m条边的有向图,点的编号是1到n,图中可能存在重边和自环。请输出任意一个该有向图的拓扑序列,如果拓扑序列不存在,则输出-1。若一个由图中所有点构成的序列A满足:对于图中的每条边(x, y),x在A中都出现在y之前,则称A是该图的一个拓扑序列。

题解:这是一个典型的拓扑排序的模板题。解法是我们可以利用向量来记录一条边的起点和终点:vec[u].push_back(v);这表示点u到点v有一条边,且u是v的先决条件,同时利用indeg[v]++,对点v的入度进行计数,这一点非常重要,因为我们要进行拓扑排序,就要从入度为0的点开始,也就是说要从没有先决条件的事件开始。之后就可以进行拓扑排序了。在进行拓扑排序的时候,我们可以用一个队列先将原图中入度为零的点存储起来(可能不止一个),这样,我们就找到了开始的起点,同时也代表我们将这一个点放进了拓扑序列,这样的话,我们此时就应该将以它为先决条件的点的入度就应该减一,如果减一后,该点的入度变为0,则在将该点放入队列,以判断队列是否为空为循环条件,每一次开始循环是队列的对头元素执行出列,循环往复的执行该循环,直到将所有的点都判断一遍,这样就可以都到一个拓扑序列了。同时,可以通过判断输出节点的个数判原图是否存在拓扑序列,若节点个数与输入的n相等,则存在,反之,不存在。

代码

#include<iostream>
#include<cstring>
#include<algorithm>
#include<vector>
#include<queue>
using namespace std;
const int maxn=1e5+10;
vector<int> vec[maxn];
queue<int> que;
queue<int> ans;
int num=0;
int indeg[maxn];
int n,m;
int topSort(){
    while(!que.empty()) que.pop();
    for(int i=1;i<=n;i++){
        if(indeg[i]==0){
            que.push(i);
        }
    }
    while(!que.empty()){
        int now=que.front();
        que.pop();
        num++;
        ans.push(now);
        for(int i=0;i<vec[now].size();i++){
            if(--indeg[vec[now][i]]==0){
                que.push(vec[now][i]);
            }
        } 
    }
    if(num==n) return 0;
    else return 1;
}
int main(){
    cin>>n>>m;
    for(int i=0;i<n;i++) vec[i].clear();
    int u,v;
    while(m--){
        cin>>u>>v;
        vec[u].push_back(v);
        indeg[v]++;
    }
    if(topSort()!=0) cout<<-1;
    else{
        int ni=ans.size();
        for(int i=0;i<ni;i++){
            cout<<ans.front();
            ans.pop();
            if(i<ni-1){
                cout<<" ";
            }
        }
    }

    return 0;
} 

更多信息可以参考博客:https://www.luogu.com.cn/blog/80049/kuai-su-ru-shou-ta-pu-pai-xu

猜你喜欢

转载自www.cnblogs.com/blogxsc/p/12815114.html