算法之判断一个图是否有环
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
算法之判断⼀个图是否有环
在⼀些经典算法中,经常需要判断⼀些图是否具有环路,⽐如拓扑排序,需要在最初判断该图是否有环路,如有有环路,则⽆法找到最长的⼀条线,⽐如dijkstra算法,每找到⼀条最短的边,都要判断找到的边和现有的树是否已经构成了环路。
因此,在这篇博客,我们重点来说⼀个判断图是否有环的算法。
⾸先我们介绍⼀个对于⽆向图和有向图通⽤的算法,先讲算法思路:
1.统计各个图中各个点的⼊度数(能够到达这个点的点的数量)。
2.然后找出⼊度数为0的点(⽆向图找⼊度数为1的点)。
3.删除⼊度数为0的点,将其边也删除。
4.重复2,直到所有点⼊度都为0,则为⽆环图,如果找不到⼊度为0的点,则为有环图。
该算法的精髓在于对于⼀个环路(以有向图为例),1->2,2->3,3->1,你会发现找不到⼀个⼊度为0的点,因此这个⽅法是可⾏的。
对于⽆向图和有向图来说,这个算法是通⽤的。
在这我只写了对于有向图的判断的算法,具体的实现代码如下:
#include<stdio.h>
using namespace std;
int graph[100][100];//⽤来存储图的数组
bool isVisited[100];//判断这个点是否已经删除
int main()
{
int n,e;
while (scanf("%d",&n)!=EOF&&n!=0)//获取点数
{
for(int i = 0;i<100;i++)
{
isVisited[i] = false;
for(int j = 0 ;j<100;j++)
{
graph[i][j] = -1;//初始化数据,所有的边都为-1,代表这两个点之间不能联通
}
}
scanf("%d",&e);//获取边数
for(int i = 0 ;i<e;i++)//构建图
{
int a,b,c;
scanf("%d %d %d",&a,&b,&c);
graph[a-1][b-1] = c;
}
int isResult = true;
for(int i = 0 ;i<n;i++)//进⾏n次循环,每次循环删除⼀个⼊度为0的点,所以进⾏n次循环
{
for(int j = 0;j<n;j++)//遍历所有的点,找⼊度为0的点
{
if(!isVisited[j])//判断该点是否删除
{
bool isCanVisited = true;//辅助变量,判断这个点是否⼊度为0
for(int k = 0;k<n ;k++)
{
if(graph[k][j]!=-1)
{
isCanVisited = false;//如果存在能够访问这个点的边,则该点⼊度不为0
}
}
if(isCanVisited)//如果该点⼊度为0,则下边是删除该点和删除其相邻边
{
for(int k = 0 ;k<n;k++)
{
graph[j][k] = -1;//删除相邻边,即将值变为-1
}
isVisited[j] = true;//删除该点
}
}
}
isResult = true;
for(int j = 0 ;j<n;j++)//进⾏循环判断当前多有点是否已经全部删除,如果全部删除,如果全部删除则跳出,否则继续循环
{
if(!isVisited[j])
{
isResult = false;
}
}
if(isResult)
break;
}
isResult = true;
for(int i = 0 ;i<n;i++)//在所有点遍历后,则通过这个循环来判断是否所有点都已经删除,如果全部删除,则为⽆环图,否则为有环图
{
if(!isVisited[i])
isResult = false;
}
if(isResult)
printf("⽆环");
if(!isResult)
printf("有环");
}
return 0;
}
实验数据(第⼀⾏输⼊n,e,n代表的是点数,e代表的是边数,接下来e⾏代表具体的边和其权值(权值暂时不⽤理会,是后续拓扑排序所有,因此当前暂时都为1)):
5 4
1 2 1
1 3 1
2 3 1
4 5 1
5 4
1 2 1
2 1 1
2 3 1
4 5 1
实验结果:。