题目大意:给一个有向图,问该图是否满足以下两个条件:1.它是一个强连通图。2.它的每一条边仅属于一个环。如果满足输出YES,否则输出NO
1. 求一遍强连通分量,只要强连通数量=1 ,就是强连通图
2. 在求强连通分量tarjan时 ,只要点u的子树能到达的祖先不等于它本身的节点层次 ,即low[u] != dnf[u] , 那么这条边就不会仅属于一个环 ,我们可以这样想想
假设点u的 low[u] < dnf[u] , 说明有一个环 起点是u的祖先-->经过u-->某个子树的点-->又回到祖先 , 这样形成的一个环 , 同时,比如 祖先到u点之间还有很多点 ,
祖先-->祖先2-->祖先3-->u ; 那么 祖先2的low 肯定是小于dnf[u]的, 也就是又存在环 祖先2的low-->..-->u--> 某个子树的点-->又回到祖先2的low ; 这样点u这个点的边就同时属于多个环 ;
# include<stdio.h>
# include<string.h>
# define N 20005
# define M 50005
# include<stack>
using namespace std;
struct node{
int from,to,next;
}edge[M];
int tol,head[N],dfn[N],low[N],flag,count,cnt,n;
bool visit[N],vis[N];
stack<int>S;
void add(int a,int b)
{
edge[tol].from=a;edge[tol].to=b;edge[tol].next=head[a];head[a]=tol++;
}
int min(int a,int b)
{
return a<b?a:b;
}
void tarjan(int u)
{
int j,v;
dfn[u]=low[u]=cnt++;
visit[u]=vis[u]=1;
S.push(u);
for(j=head[u];j!=-1;j=edge[j].next)
{
v=edge[j].to;
if(!visit[v])
{
tarjan(v);
low[u]=min(low[u],low[v]);
}
else if(vis[v])
{
low[u]=min(low[u],dfn[v]);
if(dfn[v]!=low[v]) flag=1;
}
if(flag) return;
}
if(dfn[u]==low[u])
{
count++;
do{
v=S.top();
S.pop();
vis[v]=0;
}while(v!=u);
}
}
int main()
{
int i,ncase,a,b;
scanf("%d",&ncase);
while(ncase--)
{
scanf("%d",&n);
tol=0;
memset(head,-1,sizeof(head));
while(scanf("%d%d",&a,&b)!=EOF)
{
if(!a && !b) break;
add(a,b);
}
memset(visit,0,sizeof(visit));
memset(vis,0,sizeof(vis));
flag=0;
count=0;
cnt=0;
for(i=0;i<n;i++)
if(!visit[i]) tarjan(i);
if(flag||count!=1) printf("NO\n");
else printf("YES\n");
}
return 0;
}