题: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; }