有向图或者无向图是否存在环

//判断有向图中是否存在环
#include "stdio.h"
#include "string.h"
#define VERTEX_NUM 30
//用来记录深度优先生成树的生成过程
int tree[VERTEX_NUM];
int matrix[VERTEX_NUM][VERTEX_NUM];
int visited[VERTEX_NUM];

int  has_circle (int n) {
	int i;
	for (i = 0;i < n;i++) {
		if (0 == visited[i]) {
			int t = dfs (i,n);
			if (t == 1) {
				return 1;
			}
		}
	}
	return 0;
}

//返回0没有环,返回1表示有环
int dfs (int v,int n) {
		int i;
		int t;
		visited[v] = 1;
		for (i = 0;i < n;i++) {
				if (1 ==  matrix[v][i]) {
						if (1 != visited[i]) {
								tree[i] = v;
								t = dfs (i,n);
								if (t == 1) {
										return 1;
								}
						}else {
								int w = tree[v];
								while (w != tree[w]) {
										if (w == i) {
												return 1;
										}
										w = tree[w];
								}
								if (w == i) {
										return 1;
								}
						}
				}
		}
		return 0;
}



int main () {
		int n;//顶点数
		int m;//边数
		int i;
		memset (matrix,0,sizeof(matrix));
		memset (visited,0,sizeof(visited));
		//如果tree[x] = x,表示有向图生成森林中某棵生成树的根。tree[x] = i;表示i是x顶点的父顶点。
		for (i = 0;i < VERTEX_NUM;i++) {
				tree[i] = i;
		}
		scanf ("%d%d",&n,&m);
		for (i = 0;i < m;i++) {
				int v,u;
				scanf ("%d%d",&v,&u);
				matrix[v-1][u-1] = 1;
		}
		printf ("has circle:%s\n",has_circle(n) == 1?"yes":"no");
		return 0;
}

//判断无向图中是否存在环
#include "stdio.h"
#include "string.h"
#define VERTEX_NUM 30
int matrix[VERTEX_NUM][VERTEX_NUM];
int visited[VERTEX_NUM];
int tree[VERTEX_NUM];
int has_circle (int n) {
	int i;
	for (i = 0;i < n;i++) {
		if (0 == visited[i]) {
			int t = dfs (i,n);
			if (1 == t) {
				return 1;
			}
		}
	}
	return 0;
}
int dfs (int v,int n) {
	int i;
	visited[v] = 1;
	for (i = 0;i < n;i++) {
		if (1 == matrix[v][i]) {
			if (1 == visited[i]) {//已经访问过
				int w = tree[v];
				if (w != i) {//防止i顶点是v的父亲顶点
					return 1;
				}
			}else {
				int t;
				 tree[i] = v;
				 t = dfs (i,n);
				if (t == 1) {
					return 1;
				}
			}
		}
	}
	return 0;
}
int main () {
		int n;//顶点数
		int m;//边数
		int i;
		memset (matrix,0,sizeof(matrix));
		memset (visited,0,sizeof(visited));
		for (i = 0;i < VERTEX_NUM;i++) {
			tree[i] = i;
		}
		scanf ("%d%d",&n,&m);
		for (i = 0;i < m;i++) {
				int v,u;
				scanf ("%d%d",&v,&u);
				matrix[v - 1][u - 1] = 1;
				matrix[u - 1][v - 1] = 1;
		}
		printf ("has circle:%s\n",has_circle(n) == 1?"yes":"no");
		return 0;
}


对于有向图,还可以使用拓扑排序来判断是否存在环。

update:2013-9-17 23:59


无向图中当顶点的数量和边的数量很大的时候,使用dfs存在大量的递归,会导致栈溢出。使用下面的方法可以有效的避免。

判断无向图中是否存在回路(环)的算法描述

如果存在回路,则必存在一个子图,是一个环路。环路中所有顶点的度>=2

算法:

     第一步:删除所有度<=1的顶点及相关的边,并将另外与这些边相关的其它顶点的度减一。

     第二步:将度数变为1的顶点排入队列,并从该队列中取出一个顶点重复步骤一。

     如果最后还有未删除顶点,则存在环,否则没有环。

算法分析:

            由于有m条边,n个顶点。如果m>=n,则根据图论知识可直接判断存在环路。

    (证明:如果没有环路,则该图必然是k棵树 k>=1。根据树的性质,边的数目m = n-k。k>=1,所以:m<n)

            如果m<n 则按照上面的算法每删除一个度为0的顶点操作一次(最多n次),或每删除一个度为1的顶点(同时删一条边)操作一次(最多m次)。这两种操作的总数不会超过m+n。由于m<n,所以算法复杂度为O(n)


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值