对于无向图来说,用并查集的思路,将每个结点分到不同的根节点团伙中,判断两个团伙是否有相同的根结点,如果如果两个相连接的结点有共同的根,则说明有环。
#include<bits/stdc++.h>
using namespace std;
int fa[10005];//代表元素数组
int depth[10005];//深度数组
int n,m;//n为顶点数,m为边的条数
void init()//注意初始化
{
for(int i=0;i<n;i++)
{
fa[i]=-1;
depth[i]=0;
}
}
int find_root(int x)
{
int x_root=x;
while(fa[x_root]!=-1)//只要还没找到头结点(根),那么就要一直往上找
{
x_root=fa[x_root];
}
return x_root;
}
int Union(int x,int y)
{
int x_root=find_root(x);
int y_root=find_root(y);
if(x_root==y_root)//如果需要合并的两个元素本来就是一个集合的,那么就说明存在环
{
return 0;
}else
{
if(depth[x_root]>depth[y_root])//左深右浅右插左
{
fa[y_root]=x_root;
}else if(depth[x_root]<depth[y_root])//右深左浅左插右
{
fa[x_root]=y_root;
}else
{
depth[y_root]++;//若两侧深度相同,那么我们固定x到y下面插,并且y的深度+1
fa[x_root]=y_root;
}
return 1;
}
}
int main()
{
int edge[100005][2];
cin>>n>>m;//读入顶点数和边的条数
init();
for(int i=0;i<m;i++)
{
cin>>edge[i][0]>>edge[i][1];//读入边
}
for(int i=0;i<m;i++)
{
int x=edge[i][0];
int y=edge[i][1];
if(Union(x,y)==0)
{
cout<<"有环"<<endl;
return 0;
}
}
cout<<"无环"<<endl;
return 0;
}
对于有向图来说,使用拓扑排序,visited数组记录该节点状态,1表示已经访问过,-1表示该节点所有邻接点都被访问了,0则表示未访问。
//color[i],为0表示未访问过,为1表示访问过,为-1表示该节点后边的节点都被访问过。
void DFS(int i){
cout<<"正在访问结点"<<i;
//结点i变为访问过的状态
color[i] = 1;
for(int j=1;j<=vNum;j++){
//如果当前结点有指向的结点
if(graph[i][j] != 0){
//并且已经被访问过
if(color[j] == 1){
isDAG = false;//有环
break;
}else if(color[j] == -1){
//当前结点后边的结点都被访问过,直接跳至下一个结点
continue;
}else{
DFS(j);//否则递归访问
}
}
}
//遍历过所有相连的结点后,把本节点标记为-1
color[i] = -1;
}
参考:并查集判断图中是否有环