题面网上到处都是;
主要来谈谈怎么做,首先利用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 }