bzoj 1051 (強連通) 受歡迎的牛

題目:這裏php

題意:html

Description

  每一頭牛的願望就是變成一頭最受歡迎的牛。如今有N頭牛,給你M對整數(A,B),表示牛A認爲牛B受歡迎。 這
種關係是具備傳遞性的,若是A認爲B受歡迎,B認爲C受歡迎,那麼牛A也認爲牛C受歡迎。你的任務是求出有多少頭
牛被全部的牛認爲是受歡迎的。

Input

  第一行兩個數N,M。 接下來M行,每行兩個數A,B,意思是A認爲B是受歡迎的(給出的信息有可能重複,即有可
能出現多個A,B)

Output

  一個數,即有多少頭牛被全部的牛認爲是受歡迎的。ios

Sample Input

3 3
1 2
2 1
2 3

Sample Output

1

HINT

 

100%的數據N<=10000,M<=50000

 

我是看了強連通入門(講的很清楚):http://www.2cto.com/kf/201606/517227.html算法

Kosaraju算法第一次dfs1將全部的點按拓撲排序逆序存進棧,第二次dfs2(此時是逆着方向回去搜)將整個圖分紅若干個強連通份量,。ide

對於這個題,能夠觀察出最後受到全部牛的歡迎的牛一定是在其中一個強連通份量裏面的,因此看哪一個強連通份量是其他全部變量都能達到的,也就等同於縮點後的spa

新圖裏面哪一個的出度爲0,若是出度爲0的份量只有一個,那麼該份量其中點的個數就是答案,若是出度爲0的份量個數超過一個,那麼沒有答案,輸出爲0.3d

 1 #include<cstdio>
 2 #include<cstring>
 3 #include<iostream>
 4 #include<algorithm>
 5 #include<vector>
 6 #include<map>
 7 #include<cmath>
 8 using namespace std;
 9  
10 const int M = 1e5 + 10;
11 vector<int>q;
12 int sccno[M],sum[M],du[M],scc_cnt;
13  
14 struct Edge{
15     int to,next,from,odr;
16 }edge[M*2];
17 int head1[M],head2[M],cas;
18 bool vis[M];
19  
20 void add(int u,int v)
21 {
22     edge[++cas].next=head1[u];
23     edge[cas].odr=head2[v];
24     edge[cas].to=v;edge[cas].from=u;
25     head1[u]=cas;head2[v]=cas;
26 }
27  
28 void dfs1(int u)
29 {
30     for (int i=head1[u] ; i ; i=edge[i].next){
31         int v=edge[i].to;
32         if (vis[v]) continue;
33         vis[v]=true;
34         dfs1(v);
35         q.push_back(v);
36     }
37 }
38  
39 void dfs2(int u)
40 {
41     sccno[u]=scc_cnt;
42     sum[scc_cnt]++;
43     for (int i=head2[u] ; i ; i=edge[i].odr){
44         int v=edge[i].from;
45         if (sccno[v]) continue;
46         dfs2(v);
47     }
48 }
49  
50 int main()
51 {
52     int n,m;
53     scanf("%d%d",&n,&m);
54     scc_cnt=0;cas=0;
55     q.clear();
56     while (m--){
57         int x,y;
58         scanf("%d%d",&x,&y);
59         add(x,y);
60     }
61     memset(vis,false,sizeof(vis));
62     memset(sum,0,sizeof(sum));
63     memset(du,0,sizeof(du));
64     for (int i=1 ; i<=n ; i++)
65         if (vis[i]==false){
66            vis[i]=true;dfs1(i);
67            q.push_back(i);
68         }
69  
70     for (int i=n-1 ; i>=0 ; i--){
71         if (!sccno[q[i]]){
72             scc_cnt++;
73            // cout<<q[i]<<endl;
74             dfs2(q[i]);
75         }
76     }
77  
78     for (int i=1 ; i<=cas ; i++){
79         int x=sccno[edge[i].from],y=sccno[edge[i].to];
80         if (x==y) continue;
81         du[x]++;
82     }
83     int flag=-1,ans;
84     for (int i=1 ; i<=scc_cnt ; i++)
85         if (!du[i]) flag++,ans=sum[i];
86     if (flag==0) printf("%d\n",ans);
87     else puts("0");
88     return 0;
89 }
View Code

 

Tarjan算法連接也就講的很清楚了code

 1 #include<cstdio>
 2 #include<cstdio>
 3 #include<cstring>
 4 #include<algorithm>
 5 #include<stack>
 6 using namespace std;
 7 
 8 const int M = 1e5 + 10;
 9 int head[M],cas,scc_cnt,dfs_clock;
10 int sccno[M],du[M],sum[M],lowlink[M],pre[M];
11 stack<int>s;
12 
13 int min(int x,int y){return x<y?x:y;}
14 
15 struct Edge{
16     int to,next,from;
17 }edge[M*2];
18 
19 void add(int u,int v)
20 {
21     edge[++cas].next=head[u];
22     edge[cas].to=v;edge[cas].from=u;
23     head[u]=cas;
24 }
25 
26 void dfs(int u)
27 {
28     pre[u]=lowlink[u]=++dfs_clock;
29     s.push(u);
30     for (int i=head[u] ; i ; i=edge[i].next){
31         int v=edge[i].to;
32         if (!pre[v]){
33             dfs(v);
34             lowlink[u]=min(lowlink[u],lowlink[v]);
35         }
36         else if (!sccno[v]){
37             lowlink[u]=min(lowlink[u],pre[v]);
38         }
39     }
40     if (lowlink[u]==pre[u]){
41         scc_cnt++;
42         for ( ; ; ){
43             int x=s.top();s.pop();
44             sccno[x]=scc_cnt;
45             if (x==u) break;
46         }
47     }
48 }
49 
50 int main()
51 {
52     int n,m;
53     scanf("%d%d",&n,&m);
54     cas=0,dfs_clock=0,scc_cnt=0;
55     while (m--){
56         int x,y;
57         scanf("%d%d",&x,&y);
58         add(x,y);
59     }
60     memset(pre,0,sizeof(pre));
61     memset(lowlink,0,sizeof(lowlink));
62     memset(du,0,sizeof(du));
63     memset(sum,0,sizeof(sum));
64     for (int i=1 ; i<=n ; i++)
65         if (!pre[i]) dfs(i);
66     for (int i=1 ; i<=n ; i++)
67         sum[sccno[i]]++;
68     for (int i=1 ; i<=cas ; i++){
69         int u=sccno[edge[i].from],v=sccno[edge[i].to];
70         if (u==v) continue;
71         du[u]++;
72     }
73     int flag=0,ans;
74     for (int i=1 ; i<=scc_cnt ; i++)
75         if (!du[i]) flag++,ans=sum[i];
76     if (flag==1) printf("%d\n",ans);
77     else puts("0");
78     return 0;
79 }
View Code
相關文章
相關標籤/搜索