【图论】拓扑排序
CNS_5t0_0r2 · · 算法·理论
【1】DAG,拓扑序的定义
对于一个有向无环图,我们称其为 DAG。
拓扑排序是一个有向无环图的所有顶点的线性序列。
该序列需要满足每个顶点出现且只出现一次和如果有一条
A 到B 的路径,在序列中A 出现在B 的前面。
引用来源
存在环的有向图是不存在拓扑序的。
如何求一个 DAG 的拓扑序呢?
考虑如下算法:
一开始入度为
我们将这些点删除,更新其相连节点的入度。
重复上述操作,直到所有节点被删除。
我们用一个数组存储所有点的入度,同时用一个队列。先把所有点扫一遍,把所有度数为
直到队列为空。
这里说明一下:如果发现队列空了,拓扑序长度不为点数
#include<bits/stdc++.h>
using namespace std;
const int N = 1e5 + 9,M = 1e5 + 9;
struct edge{
int to,nex;
} e[M];
int head[N],ecnt;
void addedge(int u,int v){
ecnt++;
e[ecnt] = (edge){v,head[u]};
head[u] = ecnt;
}
int n,m;
int deg[N];//入度
int ans[N],top;
void topsort(){
queue<int>q;
for(int i = 1;i <= n;i++)
if(!deg[i])
q.push(i);
while(!q.empty()){
int u = q.front();
ans[++top] = u;
q.pop();
for(int i = head[u];i;i = e[i].nex){
int v = e[i].to;
deg[v]--;
if(!deg[v])
q.push(v);
}
}
if(top != n){//存在环
cout << -1;
exit(0);
}
}
int main(){
ios::sync_with_stdio(false);
cin.tie(0);cout.tie(0);
cin >> n >> m;
for(int i = 1;i <= m;i++){
int u,v;
cin >> u >> v;
addedge(u,v);
deg[v]++;
}
topsort();
return 0;
}
例题1:家谱树
板子题,修改读入即可。
因为数据量很小,所以用邻接矩阵也可以,同时不需要判环。
#include<bits/stdc++.h>
using namespace std;
const int N = 109,M = 1e4 + 9;
struct edge{
int to,nex;
} e[M];
int head[N],ecnt;
void addedge(int u,int v){
ecnt++;
e[ecnt] = (edge){v,head[u]};
head[u] = ecnt;
}
int n,m;
int deg[N];//入度
void topsort(){
queue<int>q;
for(int i = 1;i <= n;i++)
if(!deg[i])
q.push(i);
while(!q.empty()){
int u = q.front();
cout << u << ' ';
q.pop();
for(int i = head[u];i;i = e[i].nex){
int v = e[i].to;
deg[v]--;
if(!deg[v])
q.push(v);
}
}
}
int main(){
ios::sync_with_stdio(false);
cin.tie(0);cout.tie(0);
cin >> n;
for(int i = 1;i <= n;i++){
while(1){
int v;
cin >> v;
if(!v)
break;
addedge(i,v);
deg[v]++;
}
}
topsort();
return 0;
}
例题 2:车站分级
图论建模好题。
对于一趟列车中的一个停靠站
#include<bits/stdc++.h>
using namespace std;
const int N = 1009,M = N * N;
int n,m;
bool G[N][N],park[N];
int last[N];
struct edge{
int to,nex;
} e[M];
int head[N],ecnt;
void addedge(int u,int v){
ecnt++;
e[ecnt] = (edge){v,head[u]};
head[u] = ecnt;
}
int dep[N],ans = 1;
int deg[N];
queue<int> q;
void topsort(){
for(int i = 1;i <= n;i++)
if(!deg[i]){
q.push(i);
dep[i] = 1;
}
while(!q.empty()){
int u = q.front();
q.pop();
for(int i = head[u];i;i = e[i].nex){
int v = e[i].to;
dep[v] = max(dep[v],dep[u] + 1);
ans = max(ans,dep[v]);
deg[v]--;
if(!deg[v])
q.push(v);
}
}
}
int main(){
ios::sync_with_stdio(false);
cin.tie(0);cout.tie(0);
cin >> n >> m;
while(m--){
int s;
cin >> s;
memset(park,false,sizeof park);
int node[N];
for(int i = 1;i <= s;i++){
cin >> node[i];
park[node[i]] = true;
}
for(int i = node[1];i <= node[s];i++){
if(park[i])
continue;
for(int j = 1;j <= s;j++){
if(!G[i][node[j]]){
G[i][node[j]] = true;
addedge(i,node[j]);
deg[node[j]]++;
}
}
}
}
topsort();
cout << ans;
return 0;
}