1. 程式人生 > >【CodeForces】915 D. Almost Acyclic Graph 拓撲排序找環

【CodeForces】915 D. Almost Acyclic Graph 拓撲排序找環

pri rst namespace class -- print opened codeforce get

【題目】D. Almost Acyclic Graph

【題意】給定n個點的有向圖(無重邊),問能否刪除一條邊使得全圖無環。n<=500,m<=10^5。

【算法】拓撲排序

【題解】找到一個簡單環,則欲刪除的邊一定經過該環。嘗試環上的每一條邊(至多n條邊)後再次拓撲排序判斷全圖是否有環。

拓撲排序後定位到簡單環:剩余圖是環+環內DAG,DFS過程中將走入死路的點標-1,訪問過標1,找到訪問過的點就是簡單環。換起始點直到找到環為止。

復雜度O(nm)。

技術分享圖片
#include<cstdio>
#include<queue>
#include<algorithm>
using
namespace std; const int maxn=600,maxm=100010; struct edge{int v,from;}e[maxm]; int map[maxn][maxn],tot,cnt,n,m,first[maxn],p,vis[maxn],in[maxn],deg[maxn],suc[maxn]; queue<int>Q; void insert(int u,int v){tot++;e[tot].v=v;e[tot].from=first[u];first[u]=tot;in[v]++;} void dfs(int x,int fa){ if(p||vis[x]==-1
)return; if(vis[x]==1){p=x;suc[fa]=x;return;} vis[x]=1; for(int i=first[x];i;i=e[i].from)if(deg[e[i].v]>0){ dfs(e[i].v,x); if(p){if(fa&&!suc[p])suc[fa]=x;break;} } if(!p)vis[x]=-1; } bool solve(int o){ cnt=0; for(int i=1;i<=n;i++){deg[i]=in[i];if
(i==e[o].v)deg[i]--;if(deg[i]==0)Q.push(i),cnt++;} while(!Q.empty()){ int x=Q.front();Q.pop(); for(int i=first[x];i;i=e[i].from)if(i!=o&&--deg[e[i].v]==0)Q.push(e[i].v),cnt++; } if(cnt==n)return 1; return 0; } int main(){ scanf("%d%d",&n,&m); for(int i=1;i<=m;i++){ int u,v; scanf("%d%d",&u,&v); insert(u,v);map[u][v]=tot; } cnt=0; for(int i=1;i<=n;i++){deg[i]=in[i];if(in[i]==0)Q.push(i),cnt++;} while(!Q.empty()){ int x=Q.front();Q.pop(); for(int i=first[x];i;i=e[i].from)if(--deg[e[i].v]==0)Q.push(e[i].v),cnt++; } if(cnt==n){printf("YES");return 0;} for(int i=1;i<=n;i++)if(deg[i]>0&&!p)dfs(i,0); int pp=p; do{ if(solve(map[p][suc[p]])){printf("YES");return 0;} p=suc[p]; }while(p!=pp); printf("NO"); return 0; }
View Code

另一種解法:枚舉點i,in[i]--,拓撲排序找環。這樣相當於刪除一條指向n的邊後全圖找環。

【CodeForces】915 D. Almost Acyclic Graph 拓撲排序找環