D01【模板】拓扑排序

D01【模板】拓扑排序_哔哩哔哩_bilibili

 

拓扑排序 - OI Wiki

拓扑排序(Topological sorting)给一个有向无环图的所有节点排序。

过程

1. 初始状态下,队列 q 装着所有入度为 0 的点,t 是一个空表

2. 每次从 q 中取出一个点 𝑢 放入 t,然后将 𝑢 的所有出边删除

3. 若将边 (𝑢,𝑣) 删除后点 𝑣 的入度变为 0,则将 𝑣 放入 q 中

不断重复 2,3 过程,直到队列 q 为空

检查 t 中点数是否等于 n,如果是,说明 t 中的序列就是拓扑序列,否则这个图一定有环路

应用

  1. 判断图中是否有环,还可以用来判断图是否是一条链
  2. 求带权有向无环图的最长路
  3. 求 AOE 网中的关键路径,估算工程完成的最短时间

求字典序最大/最小的拓扑排序
将队列替换成最大堆/最小堆实现的优先队列,此时时间复杂度为 𝑂(𝐸 +𝑉log𝑉)

 

B3644 【模板】拓扑排序 / 家谱树 - 洛谷

有个人的家族很大,辈分关系很混乱。给出每个人的后代的信息。输出一个序列,使得每个人的后辈都比那个人后列出。

// 拓扑排序 Kahn算法 O(V+E)
#include<bits/stdc++.h>
using namespace std;

const int N=110;
int n,rd[N];
vector<int> e[N],tp;

bool topo(){
  queue<int> q;
  for(int i=1; i<=n; i++) if(!rd[i]) q.push(i); //入度为0的点均入队
  while(q.size()){
    int u=q.front(); q.pop(); //出队
    tp.push_back(u); //记录拓扑序
    for(auto v:e[u]) if(--rd[v]==0) q.push(v); //入队
  }
  return tp.size()==n;
}
int main(){
  cin>>n;
  for(int i=1,j; i<=n; i++){
    while(cin>>j,j){
      e[i].push_back(j);
      rd[j]++; //入度
    }
  }
  topo();
  for(int i=0; i<n; i++) cout<<tp[i]<<" ";
}

 

P1807 最长路 - 洛谷

设 G 为有 n 个顶点的带权有向无环图,G 中各顶点的编号为 1 到 n,计算图 G 中 1,n 间的最长路径。

// 有向无环图的最长路 拓扑排序 O(n)
#include<bits/stdc++.h>
using namespace std;

const int N=1520,M=50010;
int n,m,a,b,c;
vector<pair<int,int>> e[N];
int rd[N],d[N];

void topo(){
  memset(d,0x80,sizeof d); //-2139062144
  d[1]=0; d[n]=-1;
  queue<int> q;
  for(int i=1;i<=n;i++) if(!rd[i]) q.push(i);
  while(q.size()){
    int u=q.front(); q.pop();
    for(auto [v,w]:e[u]){
      d[v]=max(d[v],d[u]+w);
      if(--rd[v]==0) q.push(v);
    }
  }
}
int main(){
  cin>>n>>m;
  for(int i=0;i<m;i++){
    cin>>a>>b>>c;
    e[a].push_back({b,c});
    rd[b]++; //入度
  }
  topo();
  cout<<d[n];
}

 

P4017 最大食物链计数 - 洛谷

给你一个食物网,你要求出这个食物网中最大食物链的数量。

#include<bits/stdc++.h>
using namespace std;

const int N=5005,M=80112002;
int n,m,x,y,ans;
int rd[N],cd[N],f[N]; //f[v]走到v点的路径条数
vector<int> e[N];

void topo(){
  queue<int> q;
  for(int i=1;i<=n;i++) if(!rd[i]) q.push(i),f[i]=1; //起点赋值1
  while(q.size()){
    int u=q.front(); q.pop();
    if(!cd[u]) ans=(ans+f[u])%M; //终点累计答案
    for(int v:e[u]){
      f[v]=(f[v]+f[u])%M;
      if(--rd[v]==0) q.push(v);
    }
  }
}
int main(){
  cin>>n>>m;
  for(int i=1;i<=m;i++){
    cin>>x>>y;
    e[x].push_back(y);
    rd[y]++; cd[x]++;
  }
  topo();
  cout<<ans;
}

 

P1347 排序 - 洛谷

CF1385E Directing Edges - 洛谷

 

posted @ 2022-05-28 13:07  董晓  阅读(2805)  评论(0)    收藏  举报