【tarjan+缩点】BZOJ1051-受欢迎的牛

【题意】

每一头牛的愿望就是变成一头最受欢迎的牛。现在有N头牛,给你M对整数(A,B),表示牛A认为牛B受欢迎。 这种关系是具有传递性的,如果A认为B受欢迎,B认为C受欢迎,那么牛A也认为牛C受欢迎。你的任务是求出有多少头牛被所有的牛认为是受欢迎的。

【思路】

存在于首页的经典老题,之前POJ的那道题做过之后无压力1A水过。

先用tarjan将所有联通分量进行缩点,缩点后考虑出度为0的点的个数:

(1)个数大于1的时候,显然不存在受欢迎的牛!

(2)个数等于0的时候,假设有一头牛X是受欢迎的,那么它必定有喜欢的牛Y,而它又收到牛Y的欢迎,说明存在环,不是DAG图,矛盾!

(3)个数等于1的时候,用数学归纳法推一下,有这样一个结论:出度为0的那个点可以被其它所有点到达

有了这样的结论,直接做就可以了XD

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<cstdlib>
 4 #include<cstring>
 5 #include<vector>
 6 #include<stack>
 7 #include<cmath>
 8 #include<algorithm>
 9 const int MAXN=10000+500;
10 const int MAXM=50000+500;
11 using namespace std;
12 int vis[MAXN],instack[MAXN];
13 int u[MAXM],v[MAXM]; 
14 int b[MAXN],sum[MAXN];
15 int dfn[MAXN],low[MAXN];
16 vector<int> E[MAXN];
17 stack<int> S;
18 int n,m;
19 int cnt=-1,T=0;
20  
21 void tarjan(int u)
22 {
23     dfn[u]=low[u]=++T;
24     vis[u]=1;
25     S.push(u);
26     instack[u]=1;
27      
28     for (int i=0;i<E[u].size();i++)
29     {
30         int son=E[u][i];
31         if (!vis[son])
32         {
33             tarjan(son);
34             low[u]=min(low[son],low[u]);
35         }
36         else
37         if (vis[son] && instack[son])
38             low[u]=min(dfn[son],low[u]);
39     }
40      
41     if (dfn[u]==low[u])
42     {
43         cnt++;
44         int x;
45         do
46         {
47              x=S.top();
48              S.pop();
49              sum[cnt]++;
50              b[x]=cnt;
51              instack[x]=0;
52         }while (x!=u);
53     }
54 } 
55  
56 void init()
57 {
58     memset(vis,0,sizeof(vis));
59     memset(sum,0,sizeof(sum));
60     memset(instack,0,sizeof(instack));
61     scanf("%d%d",&n,&m);
62     for (int i=0;i<m;i++)
63     {
64         scanf("%d%d",&u[i],&v[i]);
65         E[u[i]].push_back(v[i]);
66     }
67 }
68  
69 void solve()
70 {
71     int out[MAXN];
72     memset(out,0,sizeof(out));
73     for (int i=0;i<m;i++)
74         if (b[u[i]]!=b[v[i]])
75         {
76             out[b[u[i]]]++;
77         }
78  
79     int noout=0;
80     int res;
81     for (int i=0;i<=cnt;i++)
82         if (out[i]==0)
83         {
84             res=i;
85             noout++;
86         }
87     if (noout==1) cout<<sum[res]<<endl;
88         else cout<<0<<endl;
89 }
90  
91 int main()
92 {
93     init();
94     for (int i=1;i<=n;i++) if (vis[i]==0) tarjan(i);
95     solve();
96     return 0;
97 } 

 

posted @ 2016-02-21 22:50  iiyiyi  阅读(590)  评论(0编辑  收藏  举报