思路:判断一个图是否为强连通并且每条边仅属于一个环,我们把边的判断转化为对点的记录,在tarjan的过程里用一个fa数组记录每个结点的父子关系,当我们发现一条回边的时候从这个点向fa回溯,给点++,如果大于一证明这个点同时属于两个环
#include<bits/stdc++.h>
using namespace std;
const int maxn = 20000+50;
int in0[maxn],out0[maxn];
vector<int>e[maxn];
int pre[maxn],lowlink[maxn],sccno[maxn],dfs_clock,scc_cnt,fa[maxn],vis[maxn];
int flag=0;
stack<int>s;
void dfs(int u)
{
pre[u]=lowlink[u]=++dfs_clock;
s.push(u);
for(int i = 0;i<e[u].size();i++)
{
int v = e[u][i];
if(!pre[v])
{
fa[v]=u;
dfs(v);
lowlink[u]=min(lowlink[u],lowlink[v]);
}
else if (!sccno[v])
{
lowlink[u]=min(lowlink[u],pre[v]);
int tmp = u;
while(fa[tmp]!=v)
{
vis[tmp]++;
if(vis[tmp]>1)
{
flag=1;
return;
}
tmp = fa[tmp];
}
}
}
if(lowlink[u]==pre[u])
{
scc_cnt++;
for(;;)
{
int x = s.top();
s.pop();
sccno[x]=scc_cnt;
if(x==u)break;
}
}
}
void find_scc(int n)
{
dfs_clock = scc_cnt = 0;
memset(sccno,0,sizeof(sccno));
memset(pre,0,sizeof(pre));
memset(fa,-1,sizeof(fa));
memset(vis,0,sizeof(vis));
for(int i = 1;i<=n;i++)
if(!pre[i])
dfs(i);
}
int main()
{
int T;
scanf("%d",&T);
while(T--)
{
flag=0;
int n;
scanf("%d",&n);
for(int i = 0;i<=n;i++)
e[i].clear();
int u,v;
while(scanf("%d%d",&u,&v)!=EOF && u+v)
{
u++,v++;
e[u].push_back(v);
}
find_scc(n);
if(flag || scc_cnt!=1)
puts("NO");
else
puts("YES");
}
}