最受欢迎的牛 usaco

题面网上到处都是;

主要来谈谈怎么做,首先利用tarjan求强连通分量缩点,缩点后找到出度为0的点,若不止一个,则输出0,否则输出这个点包含的缩点前的点的个数;

为什么这么做,是由这道题的问法决定的,若最后求出的出度为0的点有多个,可以肯定一定没有所求的牛;

代码:

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<cstdlib>
 4 #include<cstring>
 5 #include<string>
 6 #include<algorithm>
 7 using namespace std;
 8 const int maxn=10100;
 9 int n,m;
10 int pre[maxn],low[maxn],sccno[maxn],scc_cnt=0,dfs_clock=0,z[maxn],top=0,out[maxn];
11 bool b[maxn][maxn];
12 struct node{
13     int y,next;
14 }e[maxn<<4];
15 int linkk[maxn],len=0;
16 void insert(int x,int y){
17     e[++len].y=y;
18     e[len].next=linkk[x];
19     linkk[x]=len;
20 }
21 void dfs(int x){
22     pre[x]=low[x]=++dfs_clock;
23     z[++top]=x;
24     for(int i=linkk[x];i;i=e[i].next){
25         if(!pre[e[i].y]){
26             dfs(e[i].y);
27             if(low[e[i].y]<low[x])low[x]=low[e[i].y];
28         }
29         else if(!sccno[e[i].y])
30             low[x]=min(low[x],pre[e[i].y]);
31     }
32     if(low[x]==pre[x]){
33         scc_cnt++;
34         while(true){
35             sccno[z[top]]=scc_cnt;
36             if(z[top]==x){top--;break;}
37             top--;
38         }
39     }
40 }
41 void print(int x){printf("%d
",x);exit(0);}
42 void init(){
43     scanf("%d%d",&n,&m);
44     int x,y;
45     for(int i=1;i<=m;i++){
46         scanf("%d%d",&x,&y);
47         insert(x,y);
48     }
49 }
50 void slove(){
51     for(int i=1;i<=n;i++)if(!pre[i])dfs(i);
52     int x,y;
53     for(int j=1;j<=n;j++)
54         for(int i=linkk[j];i;i=e[i].next){
55             x=sccno[j],y=sccno[e[i].y];
56             if(x==y||b[x][y])continue;
57             b[x][y]=1;out[x]++;
58         }
59     int k=0;
60     for(int i=1;i<=scc_cnt;i++){
61         if(!out[i]&&k){k=-1;break;}
62         if(!out[i]&&!k)k=i;
63     }
64     if(k==-1)print(0);
65     int sum=0;
66     for(int i=1;i<=n;i++)if(sccno[i]==k)sum++;
67     print(sum);
68 }
69 int main(){
70     init();
71     slove();
72     return 0;
73 }
View Code
原文地址:https://www.cnblogs.com/chadinblog/p/5831484.html