E. Plan of Lectures(给定拓扑图求输出序列满足存在给定链)

题:https://codeforces.com/contest/1463/problem/E

题意:给定拓扑图,在给定链(以边的形式给出),问是否能在拓扑顺序中找出一个序列使得这个序列包含给定的链(x->y->z)。

分析:

  • 给定的拓扑图我们可以当作一个DAG,然后给定的m个边我们可以在原图上进行缩点,缩成的点一定得是一条链;
  • 判断这些链会不会构成环;
  • 构建新图G,再判断是否能构成拓扑序列,再把压缩的点解压出来
#include<bits/stdc++.h>
using namespace std;
#define pb push_back
const int M=3e5+5;
int p[M],vis[M],nex[M],in[M],rt[M],rnk[M],cmp[M];
vector<int>G[M],ans;
queue<int>que;
int main(){
    int n,m;
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++) scanf("%d",&p[i]);
    for(int u,v,i=1;i<=m;i++){
        scanf("%d%d",&u,&v);
        nex[u]=v;
        vis[v]=1;///在不是链头就标记
    }
    int tot=0;
    for(int i=1;i<=n;i++){
        if(vis[i]) continue;
        cmp[i]=++tot;
        int now=0,x=nex[i];
        rnk[i]=now;
        rt[tot]=i;
        while(x!=0&&cmp[x]==0){
            rnk[x]=++now;
            cmp[x]=tot;
            x=nex[x];
        }
    }
    for(int i=1;i<=n;i++)///check circle
        if(!cmp[i]||(cmp[p[i]]==cmp[i]&&rnk[i]<rnk[p[i]])) return puts("0"),0;

    for(int i=1;i<=n;i++){///construct new graph
        if(p[i]==0) continue;
        if(cmp[i]!=cmp[p[i]]){
            G[cmp[p[i]]].pb(cmp[i]);
            in[cmp[i]]++;
        }
    }

    ///tuopu
    for(int i=1;i<=tot;i++)
        if(in[i]==0)
            que.push(i);
    while(!que.empty()){
        int u=que.front();que.pop();
        ans.pb(u);
        for(auto v:G[u])
            if(--in[v]==0) que.push(v);
    }
    if(ans.size()==tot){
        for(auto v:ans){
            int nowi=rt[v];
            while(nowi!=0){
                printf("%d ",nowi);
                nowi=nex[nowi];
            }
        }
    }
    else puts("0");
    return 0;
}
View Code
原文地址:https://www.cnblogs.com/starve/p/14159059.html