#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)。