用DFS和BFS求連通分量(鄰接表的實現與應用)

用DFS和BFS求連通分量(鄰接表的實現與應用)

本文內容改編自《挑戰程序設計競賽(第2彈)》12.5節

問題描述

給出朋友關係,判斷從指定人物出發能否通過雙向朋友鏈抵達目標人物。
輸入
第一行輸入總人數n以及朋友關係數m
人的編號從0到n-1。
接下來m行輸入朋友關係,每個朋友關係佔一行。
1個朋友關係包含s、t兩個整數,表示s和t爲朋友。
接下來一行輸入問題數q。再接下來q行輸入問題
各問題爲兩個整數s、t。表示“從s能否抵達t?”
輸出
如果從s出發能抵達t就輸出yes,否則輸出no,每個問題的回答佔1行。

限制
1 < n < 100000, 0 < m < 100000, 1 < q < 10000
樣例輸入
10 9
0 1
0 2
3 4
5 7
5 6
6 7
6 8
樣例輸出
yes
yes
no

解題思路

這道題就是求給定的圖的連通分量問題,可以用“種子填充”的思想來解決此題。
對圖中每一個結點進行深度優先搜索,並在此過程中對還沒有填色的結點填填色。
如果兩個結點有相同的顏色,那麼這兩個結點就是連通的。
於是O(1)時間就可以判斷指定兩個結點是否連通。

核心算法就是DFS。主要數據結構就是鄰接表,用來存儲圖的信息。

在鄰接表上的DFS需要需要對每個頂點,每個邊都要訪問一次,算法複雜度爲
O(|V|+|E|)

鄰接表的實現

在C++中,用vector可以輕鬆的實現鄰接表。

    vector<int> G[100]; //表示100個頂點的鄰接表
    G[u].push_back(v);  //從頂點u向頂點v畫邊
    //搜索與頂點相鄰的頂點v
    for (int i = 0; i < G[u].size(); i++) {
        int v = G[u][i];
    //...
    }

鄰接表的優缺點

優點:只需要與邊數成正比的空間
缺點:難以有效地刪除邊
若u的相鄰頂點數量爲n,需要消耗O(n)來搜索鄰接表。

代碼實現

#include <bits/stdc++.h>
using namespace std;

const int MAX_N = 100000;

int n;
vector<int> G[MAX_N];
int color[MAX_N];         
//從結點r開始DFS,並填充顏色c
void dfs(int r, int c)
{
    color[r] = c;
    for (int i = 0; i < G[r].size(); i++) {
        int v = G[r][i];
        if (color[v] == -1) {
            dfs(v, c);      //相鄰結點v未填色,則繼續搜索
        }
    }
}

void AssignColor()
{
    int id = 0;
    memset(color, -1, sizeof(color));     //初始化color數組,-1表示未填色
    for (int u = 0; u < n; u++) {
        if (color[u] == -1)                    
            dfs(u, id++);                 //對未填色的結點開始DFS
    }
}

int main()
{
    int m, s, t;

    while (cin >> n >> m) {
    //創建鄰接表
        for (int i = 0; i < m; i++) {
            cin >> s >> t;
            G[s].push_back(t);
            G[t].push_back(s);
        }
    //填色開始
        AssignColor();

        int q;
        cin >> q;
        for (int i = 0; i < q; i++) {
            cin >> s >> t;
            if (color[s] == color[t]) {
                cout << "yes" << endl;
            } else {
                cout << "no" << endl;
            }
        }
    }

    return 0;
}

其中void dfs()還有另外一種實現方法,就是顯式地使用棧來實現DFS。

當然這道題也可以用廣度優先搜索(BFS),部分代碼如下

void bfs(int r, int c)
{
    queue<int> Q;
    Q.push(r);
    color[r] = c;
    while (!Q.empty()) {
        int u = Q.front();
        Q.pop();
        for (int i = 0; i < G[u].size(); i++) {
            int v = G[u][i];
            if (color[v] == -1) {
                color[v] = c;
                Q.push(v);
            }
        }
    }
}

void AssignColor()
{
    int id = 0;
    memset(color, -1, sizeof(color));     //初始化color數組,-1表示未填色
    for (int u = 0; u < n; u++) {
        if (color[u] == -1)                    
            bfs(u, id++);                 //對未填色的結點開始BFS
    }
}
發佈了58 篇原創文章 · 獲贊 31 · 訪問量 9萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章