進行深度優先遍歷的時候,當考察的點的下一個鄰接點是已經被遍歷的點,並且不是自己之前的父親節點的時候,我們就找到了一條逆向邊,因此可以判斷該無向圖中存在環路。
visited
數組記錄了節點的訪問狀態,visited[i] = 0
表示節點i
尚未被訪問過; visited[i] = 1
表示節點i
被訪問了,但是尚未被檢測完畢; visited[i] = 2
表示節點i
已經被檢測完畢了,對於檢測完畢了的節點,其所有的臨邊都已經被考慮過了,如果存在逆向邊的話已經被檢測了,從而避免了重複地進行檢測。 father[i]
表示到達節點i
經過的前驅節點,通過反向索引father
數組,我們可以找出這個環。
#include <stdio.h>
#include <stdlib.h>
int * newIntRaw(int n)
{
return (int *)malloc(sizeof(int) * n);
}
int * newInt(int n, int init)
{
int *p = newIntRaw(n);
int i;
for (i = 0; i < n; ++i)
p[i] = init;
return p;
}
int ** newMap(int n, int m, int init)
{
int **res = (int **)malloc(sizeof(int *) * n);
int i;
for (i = 0; i < n; ++i)
res[i] = newInt(m, init);
return res;
}
typedef struct
{
int e;
int n;
int **map;
} Graph;
Graph * newGraph()
{
int n, e;
int i;
int from, to;
Graph *g = (Graph *)malloc(sizeof(Graph));
scanf("%d %d", &n, &e);
g->n = n;
g->e = e;
g->map = newMap(n, n, 0);
for (i = 0; i < e; ++i) {
scanf("%d %d", &from, &to);
g->map[from][to] = 1;
g->map[to][from] = 1;
}
return g;
}
void dispGraph(Graph *g)
{
int i, j;
for (i = 0; i < g->n; ++i) {
printf("%d: ", i);
for (j = 0; j < g->n; ++j) {
if (g->map[i][j] == 1)
printf("%d ", j);
}
printf("\n");
}
}
// ---------------------------solve-----------------------
int *visited;
int *father;
void dfs(Graph *g, int s)
{
int i;
visited[s] = 1;
for (i = 0; i < g->n; ++i) {
if (g->map[s][i] == 1) {
if (visited[i] == 0) {
father[i] = s;
dfs(g, i);
}
else if (visited[i] == 1 && i != father[s]) {
int tmp = s;
printf("find a ring: %d --> ", i);
while (tmp != i) {
printf("%d --> ", tmp);
tmp = father[tmp];
}
printf("%d\n", tmp);
}
}
}
visited[s] = 2; // 避免重複計算環
}
void findRing(Graph *g)
{
// dispGraph(g);
int i;
visited = newInt(g->n, 0);
father = newInt(g->n, -1);
for (i = 0; i < g->n; ++i)
if (visited[i] == 0)
dfs(g, i);
}
int main()
{
Graph *g = newGraph();
findRing(g);
return 0;
}
/*
5 6
0 1
0 4
4 3
3 1
1 2
3 2
*/