大概题意:n个点,m条单向的路,问任意的x和y之间是否可达。注意“The son can either go from x to y, or from y to x.”是or,不是and。所以并不是一定只能有一个强联通分量。
方法:强联通分量缩点+欧拉回路或通路。
#include<stdio.h>
#include<string.h>
#include<algorithm>
#include<vector>
using namespace std;
vector<int>e[1002];
int n,m,a,b,t,in[1002],out[1002],p[1002];
int y,ind,cnt,stack[1002],instack[1002],dfn[1002],low[1002],fa[1002];
int find(int x)
{
if(p[x]!=x) return find(p[x]);
return p[x];
}
void mege(int a,int b)
{
a=find(a);b=find(b);
if(a!=b)
p[b]=a;
}
void tarjan(int i)
{
int j,k;
dfn[i]=low[i]=++ind;
instack[i]=1;
stack[y++]=i;
for(j=0;j<e[i].size();j++)
{
k=e[i][j];
if(!dfn[k])
{
tarjan(k);
low[i]=min(low[i],low[k]);
}
else if(instack[k])
low[i]=min(low[i],dfn[k]);
}
if(dfn[i]==low[i])
{
int v;
cnt++;
do
{
v=stack[--y];
fa[v]=cnt;
instack[v]=0;
}while(i!=v);
}
}
int main()
{
scanf("%d",&t);
while(t--)
{
scanf("%d%d",&n,&m);
int i,j;
for(i=1;i<=1001;i++)
e[i].clear();
for(i=1;i<=m;i++)
{
scanf("%d%d",&a,&b);
e[a].push_back(b);
}
memset(dfn,0,sizeof(dfn));
memset(instack,0,sizeof(instack));
memset(stack,0,sizeof(stack));
memset(fa,0,sizeof(fa));
y=cnt=ind=0;
for(i=1;i<=n;i++)
{
if(!dfn[i]) tarjan(i);
}
for(i=1;i<=cnt;i++)
p[i]=i;
memset(in,0,sizeof(in));
memset(out,0,sizeof(out));
for(i=1;i<=n;i++)
{
for(j=0;j<e[i].size();j++)
{
int k=e[i][j];
if(fa[i]!=fa[k])
{
in[fa[k]]++;
out[fa[i]]++;
mege(fa[i],fa[k]);
}
}
}
int tag=0,x=0,y=0,other=0;
for(i=1;i<=cnt;i++)
{
if(find(i)==i) tag++;
if(in[i]!=out[i])
{
if(in[i]+1==out[i]) x++;
else if(in[i]-1==out[i]) y++;
else other++;
}
}
if(tag==1&&((x==0&&y==0)||(x==1&&y==1))&&other==0)
printf("Yes\n");
else
printf("No\n");
}
return 0;
}