tarjan縮點
題意:有n個牛,m個關係。並且如果a->b b->c 則a->c.
先用tarjan把各個強連通分量縮成一個點,(這個點裡的奶牛互相仰慕)並且記錄下各個強連通分量裡點的個數。
找出出度為0的強連通分量,若只有1個,則輸出該強連通分量裡點的個數。
若找到多個出度為0的強連通分量,輸出0.
//148K 16MS c++#include<iostream>#include<cstdio>#include<cstdio>#include<queue>using namespace std;#define maxn 11000#define maxm 51000int n,m;int head[maxn],v[maxm],next[maxm],cnt;int head1[maxn],v1[maxm],next1[maxm],cnt1;int dfn[maxn],low[maxn],step;int sta[maxn],top;int ID[maxn],IdNum,sum[maxn];int d[maxn],vis[maxn];int r;void Init() {memset(d,0,sizeof(d));memset(vis,0,sizeof(vis));memset(sum,0,sizeof(sum));memset(head1,-1,sizeof(head1));memset(head,-1,sizeof(head));memset(dfn,0,sizeof(dfn));memset(low,0,sizeof(low));IdNum=top=step=cnt1=cnt=0;}void add1(int a,int b){v1[cnt1]=b;next1[cnt1]=head1[a];head1[a]=cnt1++;}void add(int a,int b){v[cnt]=b;next[cnt]=head[a];head[a]=cnt++;}void tarjan(int u) {dfn[u]=low[u]=++step;sta[++top]=u;vis[u]=1;int k=0;for(int i=head[u];~i;i=next[i]){int to=v[i];if(!dfn[to])//如果沒有進過棧 {tarjan(to);//繼續找 low[u]=min(low[u],low[to]);}else if(vis[to])low[u]=min(low[u],dfn[to]);}if(dfn[u]==low[u]){IdNum++;int x;do{sum[IdNum]++;//記錄這個強連通分量的點數 x=sta[top--];vis[x]=0;ID[x]=IdNum;//表示在同一個強連通分量 }while(u!=x);}}int main(){int x,y;while(~scanf("%d%d",&n,&m)){Init();for(int i=1;i<=m;i++){scanf("%d%d",&x,&y);if(x==y)continue;add(x,y);}for(int i=1;i<=n;i++)if(!dfn[i])tarjan(i);//cout<<IdNum<<endl;for(int i=1;i<=n;i++)// 縮點建邊 for(int j=head[i];~j;j=next[j]){int to=v[j];if(ID[i]!=ID[to]){d[ID[i]]++;add1(ID[i],ID[to]);}}int flag=0;int ans;for(int i=1;i<=IdNum;i++)if(d[i]==0){flag++;ans=i;}if(flag==1)printf("%d\n",sum[ans]);elseprintf("0\n");}return 0;}