用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 
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
    }
}

你可能感兴趣的:(杂题,数据结构笔记)