dfs判断有向环
比较常用的做法是DFS,同时在DFS过程中对点染色:
- 还没被DFS访问的点是白色的,初始时所有点都是白色的
- 如果点u已经被DFS访问过,但是u的子节点还未全部被访问到,那么把u染成灰色
- 如果点u以及u的子节点都被访问过了,从u回溯到u的父节点时,将u染成黑色
如果在DFS的过程中我们沿着有向边到达了一个灰色节点,则说明图中有环;如果从未到达过灰色节点,说明没有环。
set<int> st 储存头节点标号 ,建图使用链式前向星存边 , cor储存点的颜色
对所有头节点进行dfs遍历,并记录所遍历点的数目cnt
若在某次遍历中找到环则YES ,否则检查是否所有点都被遍历cnt<n?(头节点无法找到的环)
#include<stdio.h>
#include<string.h>
#include<set>
#include<algorithm>
using namespace std;
const int MAX=1e5+5;
struct Edge
{
int to,nxt;
Edge(){}
Edge(int u,int v){to=u;nxt=v;}
Edge(Edge &x){to=x.to;nxt=x.nxt;}
}e[MAX];
int head[MAX],cor[MAX],tot,n,m,cnt,ans;
set<int>st;
set<int>::iterator p;
void init()
{
st.clear();
for(int i=1;i<=n;i++) st.insert(i);
memset(head,-1,sizeof(head));
memset(cor,0,sizeof(cor));
tot=0;cnt=0;ans=0;
}
void add(int u,int v)
{
e[tot]=Edge(v,head[u]);
head[u]=tot++;
st.erase(v);
}
bool dfs(int u)
{
++cnt;
for(int i=head[u];i!=-1;i=e[i].nxt)
{
int v=e[i].to;
if(!cor[v]) {cor[v]=-1;bool f=dfs(v);if(f)return 1;}
else if(cor[v]==-1) return 1;
}
cor[u]=1;
return 0;
}
int main()
{
int t,x,y;
scanf("%d",&t);
while(t--)
{
scanf("%d%d",&n,&m);
init();
while(m--)
{
scanf("%d%d",&x,&y);
add(x,y);
}
for(p=st.begin();p!=st.end();++p)
if(dfs(*p)){ans=1;break;}
if(!ans&&cnt<n) ans=1;
printf("%s\n",ans?"YES":"NO");
}
return 0;
}