//判断有向图中是否存在环
#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)