【BZOJ1051】1051: [HAOI2006]受欢迎的牛 tarjan求强连通分量+缩点
Description
每一头牛的愿望就是变成一头最受欢迎的牛。现在有N头牛,给你M对整数(A,B),表示牛A认为牛B受欢迎。 这种关系是具有传递性的,如果A认为B受欢迎,B认为C受欢迎,那么牛A也认为牛C受欢迎。你的任务是求出有多少头牛被所有的牛认为是受欢迎的。
Input
第一行两个数N,M。 接下来M行,每行两个数A,B,意思是A认为B是受欢迎的(给出的信息有可能重复,即有可能出现多个A,B)
Output
一个数,即有多少头牛被所有的牛认为是受欢迎的。
Sample Input
3 3
1 2
2 1
2 3
1 2
2 1
2 3
Sample Output
1
HINT
100%的数据N<=10000,M<=50000
Source
1A啦啦啦~ 新姿势tarjan算法(现在才学太弱啦!),tarjan算法求完强连通分量后进行缩点,然后查找出度为0的唯一的点(缩的点),为什么是唯一的,很简单,因为其他点都有出度,也就是其他所有点都连在一起指向该点,若不唯一,就误无解。
1 #include <iostream> 2 #include <cstdio> 3 #include <cstring> 4 #include <queue> 5 #include <stack> 6 #define N 10010 7 #define M 50050 8 using namespace std; 9 struct data1{int p,next;}e[M]; 10 int ans,cnt,n,m,scc; 11 int head[N],dfn[N],low[N],vis[N],inq[N],h[N],belong[N],ringsum[N]; 12 stack<int> q; 13 void se(int x,int y){cnt++;e[cnt].next=head[x];head[x]=cnt;e[cnt].p=y;} 14 void Tarjan(int x) 15 { 16 vis[x]=inq[x]=1; 17 low[x]=dfn[x]=++cnt;; 18 q.push(x); 19 for (int i=head[x];i!=-1;i=e[i].next) 20 { 21 if (!vis[e[i].p]) 22 { 23 Tarjan(e[i].p); 24 low[x]=min(low[x],low[e[i].p]); 25 } 26 else if (inq[e[i].p]) low[x]=min(low[x],low[e[i].p]); 27 } 28 if (dfn[x]==low[x]) 29 { 30 int now; 31 scc++; 32 while (now!=x) 33 { 34 now=q.top();q.pop(); 35 belong[now]=scc; 36 inq[now]=0; 37 ++ringsum[scc]; 38 } 39 } 40 } 41 void part1_tarjan() 42 { 43 cnt=0; 44 for (int i=1;i<=n;i++) 45 if (!vis[i]) 46 Tarjan(i); 47 } 48 void part2_shr_point() 49 { 50 for (int i=1;i<=n;i++) 51 for (int t=head[i];t!=-1;t=e[t].next) 52 if (belong[i]!=belong[e[t].p]) 53 h[belong[i]]=1; 54 } 55 void part3_doit() 56 { 57 for (int i=1;i<=scc;i++) 58 if (!h[i]) 59 { 60 if (ans) 61 { 62 ans=0; 63 return; 64 } 65 else ans=ringsum[i]; 66 } 67 } 68 int main() 69 { 70 memset(e,-1,sizeof(e)); 71 memset(head,-1,sizeof(head)); 72 scanf("%d%d",&n,&m); 73 for (int i=1;i<=m;i++) 74 { 75 int x,y; 76 scanf("%d%d",&x,&y); 77 se(x,y); 78 } 79 part1_tarjan(); 80 part2_shr_point(); 81 part3_doit(); 82 printf("%d\n",ans); 83 return 0; 84 }
—Anime Otaku Save The World.