1. 程式人生 > 實用技巧 >E. Plan of Lectures(給定拓撲圖求輸出序列滿足存在給定鏈)

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