深度優先遍歷找出一個無向圖中的環

進行深度優先遍歷的時候,當考察的點的下一個鄰接點是已經被遍歷的點,並且不是自己之前的父親節點的時候,我們就找到了一條逆向邊,因此可以判斷該無向圖中存在環路。

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
*/
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章