搜索
查看
编辑修改
首页
UNITY
NODEJS
PYTHON
AI
GIT
PHP
GO
CEF3
JAVA
HTML
CSS
搜索
我家自动化
这个屌丝很懒,什么也没留下!
关注作者
热门标签
jquery
HTML
CSS
PHP
ASP
PYTHON
GO
AI
C
C++
C#
PHOTOSHOP
UNITY
iOS
android
vue
xml
爬虫
SEO
LINUX
WINDOWS
JAVA
MFC
CEF3
CAD
NODEJS
GIT
Pyppeteer
article
热门文章
1
JS随机生成5以下的随机数_js随机数0-5
2
【DC-DC】AP5125 降压恒流驱动器 60W LED电源驱动方案PCB+BOM表
3
C语言实现六种排序算法_c语言六大排序算法程序
4
22届双非一本靠这些收获字节SSP总包50W Offer
5
Liferay Portal 6.1 CE GA2已发布
6
阿里巴巴云生态 9 大开源项目重磅发布_沈加翔
7
C语言基础(五)—— 数组、数组地址(步长+1)、字符串输入输出、随机数_c语言 数组地址
8
Unity3d游戏开发之LOD(多层次细节)优化_lod多层次细节
9
AES 加密算法原理详解及实现_aes加密
10
mongoTemplate支持多表联查 排序 条件筛选 分页 去重分组_mongotemplate多表查询
当前位置:
article
> 正文
判断有向图是否有环 、环的个数以及环中元素_判断有向图有几个环
作者:我家自动化 | 2024-02-06 21:10:51
赞
踩
判断有向图有几个环
判断有向图是否有环有三种方法:拓扑排序、深度遍历+回溯、深度遍历 + 判断后退边
这里使用 拓扑排序 和 深度遍历 + 回溯判断是不是环。使用 深度遍历 + 判断后退边找出环个数 以及环中元素
1、拓扑排序
思想:找入度为0的顶点,输出顶点,删除出边。循环到无顶点输出。
若:输出所有顶点,则课拓扑排序,无环;反之,则不能拓扑排序,有环
使用:可以使用拓扑排序为有向无环图每一个结点进行编号,拓扑排序输出的顺序可以为编号顺序
源代码:
[cpp] view plain
copy
#include <iostream>
using namespace std;
const int MAX_Vertex_Num = 20;
template<class VexType,class ArcType>
class MGraph
{
public:
void CreateGraph();//创建图
int LocateVex(VexType v);//返回顶点v所在顶点向量中的位置(下标)
void CheckCircle();
private:
VexType vexs[MAX_Vertex_Num];//顶点向量
ArcType arcs[MAX_Vertex_Num][MAX_Vertex_Num]; //这里把邻接矩阵类型用模板表示,主要是为了处理有权值的情况,比如:权值可以为小数(代价),也可以为整数
int vexnum;//顶点数
int arcnum;//边数
private:
bool TopSort();
};
template<class VexType,class ArcType>
void MGraph<VexType,ArcType>::CreateGraph()
{
VexType first;
VexType Secend;
cout<<"请输入顶点数:";
cin>>vexnum;
cout<<"请输入边数:";
cin>>arcnum;
cout<<"请输入各个顶点值:";
for (int i=0;i<vexnum;i++)
{
cin>>vexs[i];
}
//初始化邻接矩阵
for (int i=0;i<arcnum;i++)
{
for (int j=0;j<arcnum;j++)
{
arcs[i][j]=0;
}
}
cout<<"请输入边的信息:"<<endl;
for (int i=0;i<arcnum;i++)
{
cin>>first>>Secend;
//如果边有权值的话,则还应该输入权值
int x = LocateVex(first);
int y = LocateVex(Secend);
arcs[x][y]=1;//如果是有权的话,这里应该是arc[x][y]=权值
}
}
/*
参数:v:表示顶点向量中一个值
函数返回值:函数返回v在顶点向量中的下标
*/
template<class VexType,class ArcType>
int MGraph<VexType,ArcType>::LocateVex(VexType v)
{
for (int i=0;i<vexnum;i++)
{
if (vexs[i]==v)
{
return i;
}
}
return -1;
}
/*
有向图可以拓扑排序的条件是:图中没有环。
具体方法:
⑴ 从图中选择一个入度为0的点加入拓扑序列。
⑵ 从图中删除该结点以及它的所有出边(即与之相邻点入度减1)。
*/
template<class VexType,class ArcType>
bool MGraph<VexType,ArcType>::TopSort()
{
int count = 0;//拓扑排序输出顶点的个数
int top = -1;
int stack[MAX_Vertex_Num];
int indegree[MAX_Vertex_Num]={0};
//求各个顶点的入度--邻接矩阵要查询该元素的列(记录入度情况)--
//如果是邻接表,就是麻烦在这里,查询结点入度很不方便
for (int i=0;i<vexnum;i++)
{
int num=0;
for (int j=0;j<vexnum;j++)
{
if (arcs[j][i]!=0)
{
num++;
}
}
indegree[i]=num;
}
//把入度为0的顶点入栈
for (int i=0;i<vexnum;i++)
{
if (!indegree[i])
{
stack[++top]=i;//顶点的下标
}
}
//处理入度为0的结点:把入度为0的结点出栈,删除与之有关的边
while (top>-1)
{
int x = stack[top--];
cout<<vexs[x];
count++;
//把与下标为x的顶点有关的边都去掉(出边),并改变对应结点的入度
for (int i=0;i<vexnum;i++)
{
if (arcs[x][i]!=0)
{
arcs[x][i]=0;//删除到下标为i的顶点的边,这时此顶点的入度减一
indegree[i]--;
if (!indegree[i])//顶点的入度为0,则入栈
{
stack[++top]=i;
}
}
}
}
cout<<endl;
if (count == vexnum) //能拓扑排序
{
return true;
}
return false;
}
/*
检查图中是不是有环
思想:
能进行拓扑排序,则无环,反之有环
*/
template<class VexType,class ArcType>
void MGraph<VexType,ArcType>::CheckCircle()
{
if (TopSort())
{
cout<<"无环!"<<endl;
}
else
{
cout<<"有环!"<<endl;
}
}
int main()
{
MGraph<char,int> G;
G.CreateGraph();
G.CheckCircle();
system("pause");
return 1;
}
测试:
有向图:
结果:
2、深度遍历 + 回溯
思想:用回溯法,遍历时,如果遇到了之前访问过的结点,则图中存在环。
代码:
[cpp] view plain
copy
#include <iostream>
using namespace std;
const int MAX_Vertex_Num = 20;
template<class VexType,class ArcType>
class MGraph
{
public:
void CreateGraph();//创建图
int LocateVex(VexType v);//返回顶点v所在顶点向量中的位置(下标)
bool CheckCircle();//检查图中有无环
private:
VexType vexs[MAX_Vertex_Num];//顶点向量
ArcType arcs[MAX_Vertex_Num][MAX_Vertex_Num]; //这里把邻接矩阵类型用模板表示,主要是为了处理有权值的情况,比如:权值可以为小数(代价),也可以为整数
int vexnum;//顶点数
int arcnum;//边数
private:
void CheckCircle(int u,bool& isExist,bool visited[MAX_Vertex_Num],bool Isvisited[MAX_Vertex_Num]);
};
template<class VexType,class ArcType>
void MGraph<VexType,ArcType>::CreateGraph()
{
VexType first;
VexType Secend;
cout<<"请输入顶点数:";
cin>>vexnum;
cout<<"请输入边数:";
cin>>arcnum;
cout<<"请输入各个顶点值:";
for (int i=0;i<vexnum;i++)
{
cin>>vexs[i];
}
//初始化邻接矩阵
for (int i=0;i<arcnum;i++)
{
for (int j=0;j<arcnum;j++)
{
arcs[i][j]=0;
}
}
cout<<"请输入边的信息:"<<endl;
for (int i=0;i<arcnum;i++)
{
cin>>first>>Secend;
//如果边有权值的话,则还应该输入权值
int x = LocateVex(first);
int y = LocateVex(Secend);
arcs[x][y]=1;//如果是有权的话,这里应该是arc[x][y]=权值
}
}
/*
参数:v:表示顶点向量中一个值
函数返回值:函数返回v在顶点向量中的下标
*/
template<class VexType,class ArcType>
int MGraph<VexType,ArcType>::LocateVex(VexType v)
{
for (int i=0;i<vexnum;i++)
{
if (vexs[i]==v)
{
return i;
}
}
return -1;
}
/*
思想:用回溯法,遍历时,如果遇到了之前访问过的结点,则图中存在环。
引入visited数组的原因:
1)在一次深度遍历时,检测路径上是否结点是否已经被检测到,如果被重复检测,则表示有环。
2)注意,在深度递归返回时,总是要把visited置为false。
引入Isvisited数组的原因:
1)用于记录目前为止深度遍历过程中遇到的顶点。
2)因为,我们不一定以所有结点为起始点都进行一次深度遍历。
3)举例,在结点A为起点,进行深度遍历时,遇到了结点B,此时Isvisited在A和B两个位置都为true。
那么没遇到环,那么我们就不用再以B为起始点继续进行一次深度遍历了,
因为A为起点的深度遍历已经验证不会有环了。
*/
template<class VexType,class ArcType>
void MGraph<VexType,ArcType>::CheckCircle(int u,bool& isExist,bool visited[MAX_Vertex_Num],bool Isvisited[MAX_Vertex_Num])
{
visited[u]=true;
Isvisited[u]=true;
for (int j=0;j<vexnum;j++)
{
if (arcs[u][j]==1)
{
if (visited[j]==false)
{
CheckCircle(j,isExist,visited,Isvisited);
}
else
{
isExist = true;
}
}
}
visited[u]=false;//回溯,如果不写就变成一半的深度遍历,不能进行判断是否有边存在
}
template<class VexType,class ArcType>
bool MGraph<VexType,ArcType>::CheckCircle()
{
bool isExist = false;
bool Isvisited[MAX_Vertex_Num]={false};
bool visited[MAX_Vertex_Num]={false};
for (int i=0;i<vexnum;i++)
{
if (Isvisited[i]==false)
{
CheckCircle(i,isExist,visited,Isvisited);
if (isExist)
{
return true;
}
}
}
return isExist;
}
int main()
{
MGraph<char,int> G;
G.CreateGraph();
if (G.CheckCircle())
{
cout<<"图存在环!"<<endl;
}
else
{
cout<<"图不存在环!"<<endl;
}
system("pause");
return 1;
}
结果测试:
图:
结果:
3、深度遍历 + 判断后退边
思想:用DFS(深度优先遍历),判断是否有后退边,若有,则存在环
具体来说,在遍历顶点的每一条边时,判断一下这个边的顶点是不是在栈中,如果在栈中,说明之前已经访问过了,这里再次访问,说明有环存在
判断后退边时,借助一个栈和一个数组
栈:即可以用来输出环
数组:inStack判断是否在栈中
源代码:
[cpp] view plain
copy
#include <iostream>
using namespace std;
const int MAX_Vertex_Num = 20;
template<class VexType,class ArcType>
class MGraph
{
public:
void CreateGraph();//创建图
int LocateVex(VexType v);//返回顶点v所在顶点向量中的位置(下标)
void CheckCircle();
private:
VexType vexs[MAX_Vertex_Num];//顶点向量
ArcType arcs[MAX_Vertex_Num][MAX_Vertex_Num]; //这里把邻接矩阵类型用模板表示,主要是为了处理有权值的情况,比如:权值可以为小数(代价),也可以为整数
int vexnum;//顶点数
int arcnum;//边数
private:
void DFS(int x,bool visited[MAX_Vertex_Num],int stack[MAX_Vertex_Num],int& top,bool inStack[MAX_Vertex_Num],int& count);
};
template<class VexType,class ArcType>
void MGraph<VexType,ArcType>::CreateGraph()
{
VexType first;
VexType Secend;
cout<<"请输入顶点数:";
cin>>vexnum;
cout<<"请输入边数:";
cin>>arcnum;
cout<<"请输入各个顶点值:";
for (int i=0;i<vexnum;i++)
{
cin>>vexs[i];
}
//初始化邻接矩阵
for (int i=0;i<arcnum;i++)
{
for (int j=0;j<arcnum;j++)
{
arcs[i][j]=0;
}
}
cout<<"请输入边的信息:"<<endl;
for (int i=0;i<arcnum;i++)
{
cin>>first>>Secend;
//如果边有权值的话,则还应该输入权值
int x = LocateVex(first);
int y = LocateVex(Secend);
arcs[x][y]=1;//如果是有权的话,这里应该是arc[x][y]=权值
}
}
/*
参数:v:表示顶点向量中一个值
函数返回值:函数返回v在顶点向量中的下标
*/
template<class VexType,class ArcType>
int MGraph<VexType,ArcType>::LocateVex(VexType v)
{
for (int i=0;i<vexnum;i++)
{
if (vexs[i]==v)
{
return i;
}
}
return -1;
}
/*
检查图中是不是有回向边
思想:
如果有回向边,则无环,反之有环
*/
template<class VexType,class ArcType>
void MGraph<VexType,ArcType>::CheckCircle()
{
int count=0;//环的个数
int top=-1;
int stack[MAX_Vertex_Num];
bool inStack[MAX_Vertex_Num]={false};
bool visited[MAX_Vertex_Num]={false};
for (int i=0;i<vexnum;i++)
{
if (!visited[i])
{
DFS(i,visited,stack,top,inStack,count);
}
}
}
template<class VexType,class ArcType>
void MGraph<VexType,ArcType>::DFS(int x,bool visited[MAX_Vertex_Num],int stack[MAX_Vertex_Num],int& top,bool inStack[MAX_Vertex_Num],int& count)
{
visited[x]=true;
stack[++top]=x;
inStack[x]=true;
for (int i=0;i<vexnum;i++)
{
if (arcs[x][i]!=0)//有边
{
if (!inStack[i])
{
DFS(i,visited,stack,top,inStack,count);
}
else //条件成立,表示下标为x的顶点到 下标为i的顶点有环
{
count++;
cout<<"第"<<count<<"环为:";
//从i到x是一个环,top的位置是x,下标为i的顶点在栈中的位置要寻找一下
//寻找起始顶点下标在栈中的位置
int t=0;
for (t=top;stack[t]!=i;t--);
//输出环中顶点
for (int j=t;j<=top;j++)
{
cout<<vexs[stack[j]];
}
cout<<endl;
}
}
}
//处理完结点后,退栈
top--;
inStack[x]=false;
}
int main()
{
MGraph<char,int> G;
G.CreateGraph();
G.CheckCircle();
system("pause");
return 1;
}
结果测试:
有向图:
结果:
来源:http://blog.csdn.net/insistgogo/article/details/6978718
声明:
本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:
https://www.wpsshop.cn/w/我家自动化/article/detail/64585
推荐阅读
article
利用
VScode
连接
远程
服务器
进行
代码
调试及可视化界面_
vscode
连接
服务器
运行
代码
...
测试 ssh
连接
服务器
。 并输入 ,接着在命令行执行:输入密码即可
连接
服务器
。在 VSCode 的扩展页面搜索 套件并...
赞
踩
article
《
Docker
极简教程》
--
Docker
基础
--
基础
知识
(
一
)...
容器的定义容器是
一
种轻量级、可移植的软件打包技术,用于打包应用及其依赖项和运行环境,形成
一
个独立的可执行单元,被称为容器...
赞
踩
article
丹麦
计算机
硕士,
丹麦
奥尔胡斯
大学
计算机
科学专业QS世界
大学
学科
排名
...
2020年QS世界
大学
学科
排名
现已公布,奥尔胡斯
大学
再次成为顶级
大学
。QS世界
大学
学科
排名
将
计算机
科学系评为
丹麦
最好的系...
赞
踩
article
PMP
要学
多久
,
考试难吗?...
PMP
是以项目管理知识为内容的国际认证,很多人会问学习
PMP
需要
多久
的时间,我给大家解答一下吧~先说
PMP
的官方教材:P...
赞
踩
article
【
C
/
C
++
基础进阶系列】实战记录
--
跨平台
基础组件 (
命令行
解析
,
日志
,
配置文件
,
网络请求)_...
【
C
/
C
++
基础进阶系列】
跨平台
基础组件
--
命令行
解析
,
日志
,
配置文件
读写【1】
命令行
解析
【1.1】cmdline ...
赞
踩
article
从
卡牌
类
游戏
初探
游戏
服务器
_
卡牌
游戏
服务端
...
游戏
服务器
与普通
服务器
有什么区别呢?如果你想了解
游戏
开发,这个问题你一定思考过。它们之间的区别包括数据的实时性、交互性、...
赞
踩
article
【
蓝桥
杯
冲冲
冲】 [
SCOI2005
]
骑士
精神
...
今天学习动态规划,dp属于比较难的部分,这题利用记忆化搜索即可快速解决,需要多动脑,多思考思路还是很好掌握的,虽然一次性...
赞
踩
article
Ubuntu
轻松
安装
mysql8
_ubantu
安装
mysql8
...
Ubuntu
轻松
安装
mysql8
docker
安装
1.
安装
curl2.
安装
docker3. 新建网络映射4.搜索mys...
赞
踩
article
评分
卡
模型
建模、
WOE
分箱以及
模型
评估...
向AI转型的程序员都关注了这个号????????????
评分
卡
的种类——ABC
卡
A
卡
(Application score...
赞
踩
article
求无向
图
的
三元
环
个数
_怎么
求无向
图
的
三元
组
个数
...
问题描述:给定nnn个点,mmm条边
的
无向图,求
三元
环
个数
。n≤100000,m≤min(200000,n∗(n−1)/...
赞
踩
article
PyCharm
安装
教程及基本
使用
(更新至2024年新
版本
)
,
教你迈出学习
python
第一步
...
PyCharm
是一种Python IDE(Integrated Development Environment
,
集成开发...
赞
踩
article
使用C
语言
实现
阶乘
_
c
语言
阶乘
怎么写...
C
语言
实现
阶乘
_
c
语言
阶乘
怎么写
c
语言
阶乘
怎么写
阶乘
就是1*2*3*...*n=n! 代码如下...
赞
踩
article
Ubuntu 20+安装
MySQL8
及表名大小写处理_ubuntu22.04
lower
_
case
_...
1、安装#命令1sudo apt-get update#命令2sudo apt-get install mysql-se...
赞
踩
article
vscode
配置
Remote-SSH_
vscode
remote
ssh
配置
...
参考官方文档
ssh
-copy-id插件window下生成
ssh
,
配置
ssh
config详细看多个
ssh
配置
管理
配置
完就...
赞
踩
article
电视节目
制作
服务器
高
可用
性
解决方案
-数据湾_录像功能 高
可用
...
在科学技术日新月异的大背景下,网络互联、虚拟存储等先进技术陆续被开发,且成熟度处于不断提升的态势中,网络
制作
作为一种新模...
赞
踩
article
备战蓝桥杯
---
搜索
(
剪枝
)
...
3.我们用x,y计算出两者的距离
(
不考虑障碍物
)
,我们考虑反悔的时间,它是反悔后到的地方时间+偶数
(
有来必有回
)
,就算有...
赞
踩
article
什么
是
项目
管
理
?
怎么
管
?(一)_
项目
管
理
技术
究竟
是
什么
...
前言
项目
管
理
是
团队建立共同语言的需要、保证每个项目结果的需要、积累企业过程资产必要,同时还
是
打造企业战略执行力和
项目
管
理
...
赞
踩
article
Python
Turtle
绘图[难度3星]:
24
节气
倒计时
(2.使
用
字典存储数据)_如何
用
pytho...
设计灵感来源于北京
冬奥会
开幕式中
的
24
节气
倒计时
~_如何
用
python
的
for循环写
冬奥会
二十四
节气
倒计时
代码如何
用
py...
赞
踩
article
专业139总分400+
南昌大学
811
信号
与系统
考研
经验
电子信息
与
通信工程
集成电路...
专业139总分400+
南昌大学
811
信号
与系统
考研
经验
电子信息
与
通信工程
集成电路专业139总分400+
南昌大学
811
信号
...
赞
踩
article
CF#318-B -
Bear
and
Three
Musketeers
-
暴力
寻找
三元
环_如何找
三元
...
题意是给你n个点m条边求出一个
三元
环(与a相连的边包括b,c)、(与b相连的边包括a,c)(与c相连的边包括a,b)n,...
赞
踩
相关标签
ubuntu
ide
docker
java
容器
丹麦计算机硕士
项目管理
pmp
服务器
游戏
蓝桥杯
职场和发展
人工智能
大数据
python
pycharm
学习
c语言
mysql
数据库
vscode配置
ssh
剪枝
深度优先