POJ 2186 Popular Cows Tarjan+縮點
阿新 • • 發佈:2018-12-17
題意:給定一個有向圖,求有多少個頂點是任意頂點出發都可達的。
定理:有向無環圖中唯一出度為0的點,一定可以由任何點出發均可達(由於無環所以從任何點出發往前走,必然終止於一個出度為0的點。)
思路:
1.求出所有的強連通分量(用tarjan()演算法)
2.每個強連通分量縮成一點,則形成一個有向無環圖DAG。
3.DAG上面如果有唯一的出度為0的點,則該點能被所有的點可達。那麼該點所代表的連通分量上的所有的原圖中的點,都能被原圖中的所有點可達,則該連通分量的點數,就是答案。
4.DAG 上面如果有不止一個出度為0的點,則這些點互相不可達,原問題無解,答案為0。
縮點的時候不一定要構造新圖,只要把不同強連通分量的點染成不同顏色,然後考察各種顏色的點有沒有連到別的顏色的邊即可(即其對應的縮點後的DAG圖上的點是否有出邊)。
#include<stdio.h> #include<stdlib.h> #include<iostream> #include<algorithm> #include<string.h> #include<vector> using namespace std; const int maxn=10010; vector<int>g[maxn]; int n,m,x,y; int v,c[maxn],l=0,low[maxn],dfn[maxn],f[maxn]; int cnt=0,out0[maxn],sum[maxn],time_clock=0; void tarjan(int u) { low[u]=dfn[u]=++time_clock; c[++l]=u; for(int i=0;i<g[u].size();i++) { v=g[u][i]; if(!dfn[v]) { tarjan(v); low[u]=min(low[u],low[v]); }else if(!f[v]) { low[u]=min(low[u],dfn[v]); } } if(low[u]==dfn[u]) { int len=l; cnt++; while(c[l]!=u) { f[c[l--]]=cnt; } f[c[l--]]=cnt; sum[cnt]=len-l; } } int main() { scanf("%d%d",&n,&m); for(int i=1;i<=m;i++) { scanf("%d%d",&x,&y); g[x].push_back(y); } memset(dfn,0,sizeof(dfn)); for(int i=1;i<=n;i++) { if(!dfn[i]) tarjan(i); } for(int i=1;i<=n;i++) { for(int j=0;j<g[i].size();j++) { v=g[i][j]; if(f[i]!=f[v]) out0[f[i]]++; } } x=0; for(int i=1;i<=cnt;i++) { if(!out0[i]) { if(x>0) { printf("0"); return 0; } x=sum[i]; } } printf("%d",x); return 0; }