图论:拓扑排序+应用

\(01:\)拓扑排序

\(i.\)概念

从入度为0的点开始 依次删边改图进行排序 这样的排序方式就是拓扑排序

删除点的按顺序所组成的数列就是拓扑序

显然 拓扑序是不唯一的 且 可以证明一个含有闭环的图没有拓扑序

\(ii.\)实现

法1: 队列

首先用邻接表存图 \(e_u=v\)

并统计每个点的入度\(d_i\)

然后开一个拓扑序队列\(q\) 将所以入度为\(0\)的点加入队列

接着选择每次取出队头\(fr\) 将队头连接的所有点\(e_{fr}\)入度\(-1\)

如果此时有一些点的入度减为\(0\) 则将这个点存入队列

最后队列里所以点的出队顺序即为拓扑序

#include<bits/stdc++.h>
const int N=1e5+10;
using namespace std;
vector<int> e[N];
int d[N];
int main()
{
    //topo排序 方法1:队列 
    int n,m;
    cin>>n>>m;

    for(int i=1;i<=m;++i)
    {
        int u,v;
        cin>>u>>v;

        e[u].push_back(v);
        ++d[v];
    }

    queue<int> q,ans;

    for(int i=1;i<=n;++i)
        if(d[i]==0)
            q.push(i);

    while(!q.empty())
    {
        int fr=q.front();
        ans.push(fr);
        q.pop();
        for(int i=0;i<e[fr].size();++i)
        {
            int v=e[fr][i];
            --d[v];
            if(d[v]==0)
                q.push(v);
        }
    }

    int size=ans.size();
    if(size!=n)
        cout<<-1;
    else   
    while(!ans.empty())
        cout<<ans.front()<<" ",ans.pop();
    return 0;
}

法2:\(dfs\)染色法

考虑染色法 定义三种颜色状态

\(0→\)表示该点未进行操作

\(-1→\)表示该点正在操作中

\(1→\)表示该点已经完成操作

我们可以这样操作:以每个点为中心进行\(dfs\)

如果遇到了颜色为\(0\)的点就染色成\(-1\)

遇到颜色为\(-1\)的点就说明这个图中一定有环 无法进行拓扑排序

而全部染色完成后将染色点的顺序逆向存储于队列中

显然此时的存储顺序应该与图的拓扑序相反 进行reverse()操作反向即可

posted @ 2025-02-22 10:41  SamXia  阅读(62)  评论(0)    收藏  举报