#include<bits/stdc++.h> #define debu using namespace std; const int maxn=1e5+50; int s[maxn]; int v[maxn]; int dfn[maxn]; int scc[maxn]; int low[maxn]; int sum1,sum2; int n,m,all,top,num; int din[maxn],dout[maxn]; vector<int> g[maxn]; void init() { all=0; top=0; num=0; sum1=0; sum2=0; memset(s,0,sizeof(s)); memset(v,0,sizeof(v)); memset(dfn,0,sizeof(dfn)); memset(low,0,sizeof(low)); memset(scc,0,sizeof(scc)); for(int i=0; i<=n; i++) g[i].clear(); } void Find(int u) { all++; dfn[u]=all; low[u]=all; top++; s[top]=u; v[u]=true; for(int i=0; i<g[u].size(); i++) { int j=g[u][i]; if(dfn[j]==0) { Find(j); low[u]=min(low[u],low[j]); } else { if(v[j]) low[u]=min(low[u],dfn[j]); } } if(low[u]==dfn[u]) { num++; while(s[top+1]!=u) { scc[s[top]]=num; v[s[top]]=false; top--; } } } void make() { for(int i=1; i<=n; i++) if(dfn[i]==0) Find(i); } void solve() { memset(din,0,sizeof(din)); memset(dout,0,sizeof(dout)); for(int u=1; u<=n; u++) for(int j=0; j<g[u].size(); j++) { int v=g[u][j]; if(scc[u]!=scc[v]) { dout[scc[u]]=1; din[scc[v]]=1; } } for(int i=1; i<=num; i++) { if(!din[i]) sum1++; if(!dout[i]) sum2++; } int ans=(num!=1)?max(sum1,sum2):0; printf("%d\n",ans); } int main() { #ifdef debug freopen("in.in","r",stdin); #endif // debug int t; scanf("%d",&t); while(t--) { init(); scanf("%d%d",&n,&m); for(int i=0; i<m; i++) { int x,y; scanf("%d%d",&x,&y); g[x].push_back(y); } make(); solve(); } return 0; }
题目地址:https://icpcarchive.ecs.baylor.edu/index.php?option=com_onlinejudge&Itemid=8&page=show_problem&problem=2288
题解:Tarjan求强连通分量后缩点,设缩点后DAG图中入度为0点个数为sum1,出度为0点个数为sum2,则ans=max(sum1,sum2)(注意当原图已经强连通时,ans=0)。