用并查集判断一个无向图中是否存在环

并查集是一种树型的数据结构,用于处理一些不相交集合(Disjoint Sets)的合并及查询问题。常常在使用中以森林来表示。集就是让每个元素构成一个单元素的集合,也就是按一定顺序将属于同一组的元素所在的集合合并。

  • Find:确定元素属于哪一个子集。它可以被用来确定两个元素是否属于同一子集合。
  • Union:将两个子集合并成同一个集合。

其实判断一个图是否存在环已经有相应的算法,此文用并查集来判断一个图是否有环。

我们可以用一个一维数组parent[] 来记录子集合。

看下面这个图:

0

|   \

|     \

1——2

对每一条边的两个顶点加入集合,发现两个相同的顶点在一个子集合中,就说明存在环。

初始化:parent[n] 的每个元素都为-1,共有n个子集合,表示集合只有当前顶点一个元素

0    1     2

-1   -1   -1

然后逐个处理每条边。

边0-1:我们找到两个子集合 0 和1,因为他们在不同的子集合,现在需要合并他们(Union). 把其中一个子集合作为对方的父集合.

0    1   2     <----- 1 成为 0 的 父集合 (1 现在代表集合 {0, 1})

1    -1  -1

边0-2:1属于属于子集合1,2属于子集合2,因此合并他们。

0   1    2     <----- 2 作为 1的父集合 (2 现在代表集合 {0, 1, 2})

1   2   -1

 边0-2: 0是在子集和2和2也是在子集合2, 因为 0->1->2 // 1 是0 父集合 并且  2 是1的父集合 。因此,找到了环

// 用并查集判断是否存在环
002
#include <stdio.h>
003
#include <stdlib.h>
004
#include <string.h>
005

006
// 图中的边
007
struct Edge
008
{
009
    int src, dest;
010
};
011

012
// 图结构体
013
struct Graph
014
{
015
    // V-> 顶点个数, E-> 边的个数
016
    int V, E;
017

018
    // 每个图就是 边的集合
019
    struct Edge* edge;
020
};
021

022
// 创建一个图
023
struct Graph* createGraph(int V, int E)
024
{
025
    struct Graph* graph = (struct Graph*) malloc( sizeof(struct Graph) );
026
    graph->V = V;
027
    graph->E = E;
028

029
    graph->edge = (struct Edge*) malloc( graph->E * sizeof( struct Edge ) );
030

031
    return graph;
032
}
033

034
// 查找元素i 所在的集合( 根 )
035
int find(int parent[], int i)
036
{
037
    if (parent[i] == -1)
038
        return i;
039
    return find(parent, parent[i]);
040
}
041

042
// 合并两个集合
043
void Union(int parent[], int x, int y)
044
{
045
    int xset = find(parent, x);
046
    int yset = find(parent, y);
047
    parent[xset] = yset;
048
}
049

050
// 检测环
051
int isCycle( struct Graph* graph )
052
{
053
    int *parent = (int*) malloc( graph->V * sizeof(int) );
054

055
    // 初始化所有集合
056
    memset(parent, -1, sizeof(int) * graph->V);
057

058
    // 遍历所有边
059
    for(int i = 0; i < graph->E; ++i)
060
    {
061
        int x = find(parent, graph->edge[i].src);
062
        int y = find(parent, graph->edge[i].dest);
063

064
        if (x == y) //如果在一个集合,就找到了环
065
            return 1;
066

067
        Union(parent, x, y);
068
    }
069
    return 0;
070
}
071

072
// 测试
073
int main()
074
{
075
    /* 创建一些的图
076
         0
077
        |  078
        |    079
        1-----2 */
080
    struct Graph* graph = createGraph(3, 3);
081

082
    // 添加边 0-1
083
    graph->edge[0].src = 0;
084
    graph->edge[0].dest = 1;
085

086
    // 添加边 1-2
087
    graph->edge[1].src = 1;
088
    graph->edge[1].dest = 2;
089

090
    // 添加边 0-2
091
    graph->edge[2].src = 0;
092
    graph->edge[2].dest = 2;
093

094
    if (isCycle(graph))
095
        printf( "Graph contains cycle" );
096
    else
097
        printf( "Graph doesn‘t contain cycle" );
098

099
    return 0;
100
}

时间: 2024-11-07 03:14:38

用并查集判断一个无向图中是否存在环的相关文章

利用并查集判断一个无向图是否成树

hdu 1272 利用并查集方法,找到各点的根节点. 几点注意: 一.树:1.无环 2.根节点入度为0,其余入度为1 判断依据: 1.若两个点的根节点相同(这两个点是父子关系),则形成环. 2.若所有点中只有一个点的根节点是他本身,则根节点入度为0. 二. 1. 0 0 :空树也是一颗树. 1 #include<iostream> 2 #include<algorithm> 3 #define Max 100005 4 using namespace std; 5 6 int f[

并查集(判断一个图有几个连通块)

import java.util.Scanner; // 并查集 判断一个图中有几个联通块 public class UnionFind { private int[] father;// private int count;// 分量数量 public UnionFind(int N){ count=N; father=new int[N]; for(int i=0;i<N;i++){ father[i]=i; } } public int count() { return count; }

利用并查集判断一个有向图是否成树

hdu 1325 此题与hdu 1272类似. 1 #include<stdio.h> 2 #include<string.h> 3 #define N 110000 4 int f[N],vis[N]; 5 int flag = 0; 6 int Maxx = 0; 7 int num = 1; 8 int Max(int a,int b) 9 { 10 return a>b?a:b; 11 } 12 void star1() 13 { 14 int i; 15 for(i

hdu 5424 回溯+并查集判断连通性

题意:给定一个n个点n条边的无向图,判断是否存在哈密顿路径. 思路:先用并查集判断图是否连通,然后从度数最小的点开始回溯,看是否能找到一条哈密顿路径. 1 #include <iostream> 2 #include <cstring> 3 #include <cstdio> 4 #include <set> 5 using namespace std; 6 7 const int INF = 999999; 8 const int N = 1001; 9

并查集-判断图的连通

来看一个实例,杭电1232畅通工程 首先在地图上给你若干个城镇,这些城镇都可以看作点,然后告诉你哪些对城镇之间是有道路直接相连的.最后要解决的是整幅图的连通性问题.比如随意给你两个点,让你判断它们是否连通,或者问你整幅图一共有几个连通分支,也就是被分成了几个互相独立的块.像畅通工程这题,问还需要修几条路,实质就是求有几个连通分支.如果是1个连通分支,说明整幅图上的点都连起来了,不用再修路了:如果是2个连通分支,则只要再修1条路,从两个分支中各选一个点,把它们连起来,那么所有的点都是连起来的了:如

HDU Catch (二分图判断奇环+并查集判断联通)

Problem Description A thief is running away!We can consider the city where he locates as an undirected graph in which nodes stand for crosses and edges stand for streets. The crosses are labeled from 0 to N–1. The tricky thief starts his escaping fro

poj 2513 欧拉回路+并查集判断是否联通+Trie树

http://poj.org/problem?id=2513 最初看到 第一感觉---map  一看250000的数据量 果断放弃 然后记得以前看过,trie代替map,尤其当数据量特别大的时候 学到了: 1.Trie代替map的思想,可以在单词结尾的tree[i][tk]  这个i作为字符串对应的int值 ,当然这个int值也可以用于建立并查集 2.接上,通过并查集判断,所有的点在同一个集合图就是联通的,否则不联通,注意tree[i][tk]>0 表示是单词结尾, x=Find(x);//这句

算法积累(字符串转换驼峰,判断一个字符串中那个字母出现次数最多,并且出现了几次)

因为算法比较烂,所以想做一下这方面的积累. 尽量能够每天学习一个新算法吧.(不过估计很悬) 好吧,今天第一个是字符串转换驼峰 直接上代码 var str = 'toupper-case'; var arr = str.split('-'); //toupper,case for (var i = 1; i < arr.length; i++) { //把除了第一个数组后面的数组的第一个值设置为大写然后大写字母和去掉第一个字符的剩下的字符进行拼合 arr[i] = arr[i].charAt(0)

HDU1558 - Segment set 并查集 + 判断线段相交

HDU1558 - Segment set: http://acm.hdu.edu.cn/showproblem.php?pid=1558 题目大意: 输入一些线段的端点坐标,若两线段相交,则把他们合并成一个集合,输入数据里会有k,问和k线段相交的线段的数目(包括自己) 思路: 每次输入一条线段,都从头扫描一次. 找出之前输入的线段里面,所有和其相交的线段,并且合并(合并用的是线段的ID). 就是: 并查集 + 判断线段相交 代码: #include <iostream> #include &