图论:拓扑排序+应用
\(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()操作反向即可