题意:给出一个有向图,问最多能有多少点能构成一个集合,这个集合性质是任意两点能相互到达,即u->v or v->y.
分析:任意两点能互相到达,而且是有向图,很容易想到是强连通。要使这个集合中的点最多,仅一个强连通分量肯定不行,可由多个强连通分量构成. 那么求出各个强连通分量后,缩点,然后深搜一次,找出最大点集。
#include <iostream>
#include <stdio.h>
#include <math.h>
#include <algorithm>
#include <queue>
#include <stack>
#include <vector>
#include <string>
#include <string.h>
#include <map>
#include <set>
using namespace std;
#define maxn 2002
#define inff 0x3FFFFFFF
int dfn[maxn],low[maxn],vis[maxn],succ[maxn],bic[maxn];
stack<int>sta;
vector<int>E[100000];
int tim,ans,maxx,cnt;
struct node
{
int en,next;
}edge[100000];
int p[maxn],num;
void init()
{
num=0;
memset(p,-1,sizeof(p));
}
void add(int st,int en)
{
edge[num].en=en;
edge[num].next=p[st];
p[st]=num++;
}
void tarjan(int u,int fa)
{
low[u]=dfn[u]=++tim;
vis[u]=1;
sta.push(u);
int j,v;
for(j=p[u];j+1;j=edge[j].next)
{
v=edge[j].en;
// if(v==fa)continue;//不判断父亲节点比如 1->2,2->1 他们在一个连通块
if(!dfn[v])
{
tarjan(v,u);
low[u]=min(low[u],low[v]);
}
else
if(vis[v])
low[u]=min(low[u],dfn[v]);
}
if(low[u]==dfn[u])
{
cnt++;
while(!sta.empty())
{
int x=sta.top();
sta.pop();
succ[x]=cnt;
vis[x]=0;
if(x==u)break;
}
}
}
void dfs(int i,int temp)
{
int j;
int len=E[i].size();
temp+=bic[i];
ans=max(ans,temp);
for(j=0;j<len;j++)
{
int v=E[i][j];
dfs(v,temp);
}
}
int main()
{
int n,m,i,t,j;
cin>>t;
while(t--)
{
cin>>n>>m;
if(n==0){cout<<0<<endl;continue;}
init();
for(i=1;i<=m;i++)
{
int a,b;
cin>>a>>b;
add(a,b);
}
memset(low,0,sizeof(low));
memset(dfn,0,sizeof(dfn));
memset(vis,0,sizeof(vis));
memset(bic,0,sizeof(bic));
tim=0;cnt=0;
while(!sta.empty())sta.pop();
for(i=1;i<=n;i++)
{
if(!dfn[i])
{
tarjan(i,-1);
}
}
for(i=1;i<=n;i++)
{
bic[succ[i]]++;
}
for(i=0;i<100000;i++)E[i].clear();
for(i=1;i<=n;i++)
{
for(j=p[i];j!=-1;j=edge[j].next)
{
int v=edge[j].en;
if(succ[i]!=succ[v])
E[succ[i]].push_back(succ[v]);
}
}
ans=0;
for(i=1;i<=cnt;i++)
{
dfs(i,0);
}
cout<<ans<<endl;
}
return 0;
}