判断无向图是否有环路的方法 -并查集 -BFS
可以利用并查集或者带颜色标记的BFS(来自算法导论)判断。
首先介绍第一种,用并查集来判断:
首先初始化所有元素的根为-1,-1代表根节点,接下来对于图中的每一条边(v1,v2)都并入集合,并入的方式为查找v1和v2的根节点,然后让v2的根节点作为v1的根节点,查找根节点的过程为:如果当前的结点根为-1,说明这个结点就是根,直接返回,否则再继续查找结点父亲的根,直到找到祖先结点,这里因为只是判断环路,不需要压缩路径:
int findSet(int x){ if(Parent[x] == -1){
return x; // x is root
}
return findSet(Parent[x]); }
在找到v1的根vp1和v2的根vp2以后,首先判断他们是否是同根的,对于一个无环图,某条边并入集合前是不会出现同根的情况的,这是因为这条边中一定有一个结点是新加入集合的(否则这条边就重复了),这个结点的根一定为-1,而另一个已经并入的,会存着根结点的序号(不一定是祖先,因为没有压缩路径),只有图有环的时候才可能两个根相同,因此以vp1是否等于vp2作为图是否有环的依据,一旦发现,即说明有环,直接返回,没有则合并v1、v2,继续进行。
注意:虽然是无向图,但是边只能单向遍历,如果把两个方向的边都遍历,势必有一边出现同根的两结点,一定要注意!!!
具体代码如下:
#include <iostream>
#include <vector>
#include <memory.h> using namespace std; vector<int> Parent; void initSet(){ for(int i = 0; i < Parent.size(); i++)
Parent[i] = -1; } int findSet(int x){ if(Parent[x] == -1){
return x; // x is root
}
return findSet(Parent[x]); } void UnionSet(int x, int y){ int xp = findSet(x);
int yp = findSet(y);
Parent[xp] = yp; } int main(){ int N, E;
cin >> N >> E;
vector<vector<int> > edges(N);
Parent.resize(N);
int v1,v2;
for(int i = 0; i < E; i++){
cin >> v1 >> v2;
edges[v1].push_back(v2);
//edges[v2].push_back(v1);
}
// 测试是否有环
initSet();
for(int v = 0; v < edges.size(); v++){
for(int i = 0; i < edges[v].size(); i++){
int w = edges[v][i];
int xp = findSet(v);
int yp = findSet(w);
if(xp == yp){
cout << "未合并前同根,说明有环。" << endl;
return 0;
}
UnionSet(v,w);
}
}
cout << "无环" << endl;
return 0; }
第二种方法,是利用BFS。
我们规定结点有三种颜色,白色、灰色、黑色,在结点没有访问之前,为白色,当结点入队时,结点变灰,出队时变黑。
因为BFS是按层的顺序、从左到右进行遍历的,因此当一个根结点变黑后,也就是它出队以后,接下来要将它的所有未访问过的子结点(邻接点)入队,并且染上灰色,下面我们讨论任一个子结点的颜色。
如果没有环,子结点的颜色只可能是白色,也就是未访问过,如果子结点的颜色为灰色,说明入队过,可能是在根结点变黑(出队)之前就有一个结点有这个子结点作为邻接点,从而进行了第一次访问,这也就是有环的情况,因此,只需要在BFS过程中检测出队结点的邻接点是否有灰色结点即可,有灰色结点可理解得出有环的结论。
具体代码如下:
bool hasCycle(int s){ for(int i = 1; i <= N; i++) {
nodesColor[i] = colorWhite;
} queue<int> Q;
Q.push(s);
while(!Q.empty()){ int v = Q.front();
Q.pop();
nodesColor[v] = colorGray;
for(int index = 0; index < Graph[v].size(); index++){
int w = Graph[v][index];
if(nodesColor[w] == colorWhite){
Q.push(w);
nodesColor[w] = colorGray;
}else if(nodesColor[w] == colorGray){
return true;
}
}
nodesColor[v] = colorBlack;
} return false; }
判断无向图是否有环路的方法 -并查集 -BFS的更多相关文章
- UVA - 10004 Bicoloring(判断二分图——交叉染色法 / 带权并查集)
d.给定一个图,判断是不是二分图. s.可以交叉染色,就是二分图:否则,不是. 另外,此题中的图是强连通图,即任意两点可达,从而dfs方法从一个点出发就能遍历整个图了. 如果不能保证从一个点出发可以遍 ...
- hdu 1272 判断所给的图是不是生成树 (并查集)
判断所给的图是不是生成树,如果有环就不是,如果没环但连通分量大于1也不是 find函数 用递归写的话 会无限栈溢出 Orz要加上那一串 手动扩栈 Sample Input6 8 5 3 5 2 6 4 ...
- UVA 1160 - X-Plosives 即LA3644 并查集判断是否存在环
X-Plosives A secret service developed a new kind ofexplosive that attain its volatile property only ...
- 判断图连通的三种方法——dfs,bfs,并查集
Description 如果无向图G每对顶点v和w都有从v到w的路径,那么称无向图G是连通的.现在给定一张无向图,判断它是否是连通的. Input 第一行有2个整数n和m(0 < n,m < ...
- JS判断字符串长度的5个方法
这篇文章主要介绍了JS判断字符串长度的5个方法,并且区分中文和英文,需要的朋友可以参考下 目的:计算字符串长度(英文占1个字符,中文汉字占2个字符) 方法一: 代码如下: String.pr ...
- js 判断数组包含某值的方法 和 javascript数组扩展indexOf()方法
var questionId = []; var anSwerIdValue = []; ////javascript数组扩展indexOf()方法 Array.prototype.indexOf ...
- 字符串--java中判断字符串是否为数字的方法的几种方法?
ava中判断字符串是否为数字的方法: 1.用JAVA自带的函数 public static boolean isNumeric(String str){ for (int i = 0; i < ...
- php判断是否为json格式的方法
php判断是否为json格式的方法. 首先要记住json_encode返回的是字符串, 而json_decode返回的是对象 判断数据不是JSON格式: 复制代码代码如下: function is_n ...
- Underscore.js 常用类型判断以及一些有用的工具方法
1. 常用类型判断以及一些有用的工具方法 underscore.js 中一些 JavaScript 常用类型检查方法,以及一些工具类的判断方法. 首先我们先来谈一谈数组类型的判断.先贴出我自己封装好的 ...
随机推荐
- OC基础之推荐一个旋转木马(跑马灯)效果的图片展示Demo
这个旋转木马(跑马灯)效果的图片展示Demo,包括设定旋转方向,图片倒影,背景设置,旋转速度,开始结束,点击显示选中的图片,彩色的块展示等等功能 效果图:(源码下载:https://github.co ...
- ubuntu垃圾清理命令
ubuntu的空间莫名不够用了 通过系统自带的工具磁盘使用分析器,发现var文件下面的log100多个g,这个日志文件是可以删除的,然后tmp文件也是可以删除的. 1.sudo rm -rf /tmp ...
- 剑指Offer——知识点储备-常用算法
剑指Offer--知识点储备-常用算法 快速排序 注:若排序是有序的,采用快排,则退化为冒泡排序. 解决这个问题,采用两个选取基准的方法 (1)随机选取基数(在这个区间内随机取一个数) 出现的恶劣情况 ...
- Markdown对应Yelee主题语法
概述 这里说的是Yelee主题的语法和原生语法是有些区别的:更多的基础语法可以到Cmd Markdown上面去查看:但是我觉得都会各有不同吧 注意这里说的不是真正意义上的Markdown语法 标题 一 ...
- 使用Android Studio向GitHub提交代码
使用Android Studio向GitHub提交代码 在GitHub上创建一个仓库 填写仓库名称.描述.类型(公有.私有)等信息,点击创建 到此,成功创建了我们的仓库,并且初始化创建了README. ...
- activiti 多实例任务
1.1.1. 前言 个人,那么当5个人都投票的时候大概分为如下几种: 1.部门所有人都去投票,当所有人都投票完成的时候,这个节点结束,流程运转到下一个节点.(所有的人都需要投票) 2.部门所有人都去投 ...
- SpriteKit塔防游戏动态改变防御塔价格标签的颜色
大熊猫猪·侯佩原创或翻译作品.欢迎转载,转载请注明出处. 如果觉得写的不好请多提意见,如果觉得不错请多多支持点赞.谢谢! hopy ;) 本篇blog在DinoDefense塔防游戏基础之上做一处小的 ...
- SQLite 表达式(http://www.w3cschool.cc/sqlite/sqlite-expressions.html)
SQLite 表达式 表达式是一个或多个值.运算符和计算值的SQL函数的组合. SQL 表达式与公式类似,都写在查询语言中.您还可以使用特定的数据集来查询数据库. 语法 假设 SELECT 语句的基本 ...
- Android之触摸手势检测GestureDetector使用详解
在Android中,当用户触摸屏幕的时候,会产生许多手势,例如down,up,scroll,filing,onSingleTapConfirmed(单击),onDoubleTap(双击)等等. 一般情 ...
- Android实现自动更新功能
Android实现自动更新功能 Android自动更新的功能可以使用第三方的SDK来实现,但是类似友盟,就不支持x86手机的自动更新,科大讯飞,弹窗是全局的,小米手机就会默认把弹窗权限关掉不允许弹出提 ...