题目链接:http://acm.hust.edu.cn/vjudge/problem/viewProblem.action?id=10294
【思路】
强连通分量。
求出bcc后,缩点形成DAG,设DAG上入度为0的点数为a 出度为0的点数为b,则ans=max(a,b) (互相到达,首尾相接),需要注意scc数为1的时候ans=0。
【代码】
1 #include<cstdio> 2 #include<stack> 3 #include<vector> 4 #include<cstring> 5 #include<iostream> 6 using namespace std; 7 8 const int maxn = 20000+10; 9 10 int pre[maxn],lowlink[maxn],sccno[maxn],dfs_clock,scc_cnt; 11 vector<int> G[maxn]; 12 stack<int> S; 13 14 int dfs(int u) { 15 pre[u]=lowlink[u]=++dfs_clock; 16 S.push(u); 17 for(int i=0;i<G[u].size();i++) { 18 int v=G[u][i]; 19 if(!pre[v]) { 20 dfs(v); 21 lowlink[u]=min(lowlink[u],lowlink[v]); 22 } 23 else if(!sccno[v]) { 24 lowlink[u]=min(lowlink[u],pre[v]); 25 } 26 } 27 if(lowlink[u]==pre[u]) { 28 scc_cnt++; 29 for(;;) { 30 int x=S.top(); S.pop(); 31 sccno[x]=scc_cnt; 32 if(x==u) break; 33 } 34 } 35 } 36 void find_scc(int n) { 37 memset(pre,0,sizeof(pre)); 38 memset(sccno,0,sizeof(sccno)); 39 scc_cnt=dfs_clock=0; 40 for(int i=0;i<n;i++) 41 if(!pre[i]) dfs(i); 42 } 43 44 int T,n,m; 45 int in0[maxn],out0[maxn]; 46 47 int main() { 48 scanf("%d",&T); 49 while(T--) { 50 scanf("%d%d",&n,&m); 51 for(int i=0;i<n;i++) G[i].clear(); 52 int u,v; 53 for(int i=0;i<m;i++) { 54 scanf("%d%d",&u,&v); 55 u--,v--; 56 G[u].push_back(v); 57 } 58 find_scc(n); 59 for(int i=1;i<=scc_cnt;i++) in0[i]=out0[i]=1; 60 for(int i=0;i<n;i++) { 61 int u=sccno[i]; 62 for(int j=0;j<G[i].size();j++) { 63 int v=sccno[G[i][j]]; 64 if(u!=v) out0[u]=in0[v]=0; 65 } 66 } 67 int a=0,b=0; 68 for(int i=1;i<=scc_cnt;i++) 69 a+=in0[i],b+=out0[i]; 70 int ans=scc_cnt==1? 0:max(a,b); 71 printf("%d ",ans); 72 } 73 return 0; 74 }