用DFS和BFS求连通分量(邻接表的实现与应用)

来源:互联网 发布:淘宝花呗怎么还款 编辑:程序博客网 时间:2024/05/07 02:27

用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,并填充颜色cvoid 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    }}
0 0