You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

5.3 KiB

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

图的连通性判断

总结

  • 常用的判连通办法有四种,分别是并查集、dfsbfsfloyd
  • 最常用的是dfs、并查集
  • 前三种适合稀疏图,floyd适合稠密图

一、并查集

#include <bits/stdc++.h>

using namespace std;

const int N = 1010; // 图的最大点数量
/**
 共提供两组数据样例1为不连通用例样例2为连通用例

 样例1不连通5号结点为独立的
 5 4
 1 2
 2 3
 3 4
 1 4

 样例2连通不存在独立结点
 5 4
 1 2
 2 3
 3 4
 1 5

 检测各种算法是否能准确获取结果
 */
int n;    // n个人
int m;    // m个亲戚
int x, y; // 输入两个人之间的关系
int p[N]; // 并查集数组
// 要深入理解这个递归并压缩的过程
int find(int x) {
    if (p[x] != x)         // 如果x不是族长,递归找父亲,副产品就是找回的结果更新掉自己的家族信息。
        p[x] = find(p[x]); // 非常经典的更新,路径压缩大法!
    // 返回族长是谁
    return p[x];
}

int cnt;

int main() {
#ifndef ONLINE_JUDGE
    // freopen("BCJ1.in", "r", stdin);
    freopen("BCJ2.in", "r", stdin);
#endif
    // n个人员m个关系
    cin >> n >> m;
    // 并查集初始化
    for (int i = 1; i <= n; i++) p[i] = i; // 自己是自己的老大
    // 录入m种关系,使用并查集来判断图的连通性
    for (int i = 1; i <= m; i++) {
        cin >> x >> y;
        // 加入并查集
        int px = find(x), py = find(y);
        if (px != py) p[px] = py;
    }
    // 图已经搭好了,接下来看它们根节点是否相同,如只有一个相同的根节点,则说明是一个连通图
    for (int i = 1; i <= n; i++)
        if (p[i] == i) cnt++;

    if (cnt == 1)
        printf("图是连通的\n");
    else
        printf("图不是连通的\n");
    return 0;
}

二、dfs

#include <bits/stdc++.h>

using namespace std;

const int N = 1010, M = N << 2; // 图的最大点数量
// 链式前向星
int e[M], h[N], idx, w[M], ne[M];
void add(int a, int b, int c = 0) {
    e[idx] = b, ne[idx] = h[a], w[idx] = c, h[a] = idx++;
}
int n, m; // 表示图中有n个点m条边
bool st[N];
int cnt;
// 深度遍历
void dfs(int u) {
    st[u] = 1;
    cnt++; // 多走了一个结点
    for (int i = h[u]; ~i; i = ne[i]) {
        int v = e[i];
        if (!st[v])
            dfs(v);
    }
}

int main() {
#ifndef ONLINE_JUDGE
    freopen("in1.in", "r", stdin);
    // freopen("in2.in", "r", stdin);
#endif
    // 初始化链式前向星
    memset(h, -1, sizeof h);
    // 采用邻接表建图
    cin >> n >> m;
    // m条边
    for (int i = 1; i <= m; i++) {
        int a, b;
        cin >> a >> b;
        add(a, b);
    }

    // 利用dfs进行检查是不是强连通的
    dfs(1);

    if (cnt == n)
        printf("图是连通的\n");
    else
        printf("图不是连通的\n");
    return 0;
}

三、bfs

#include <bits/stdc++.h>

using namespace std;

const int N = 1010, M = N << 2; // 图的最大点数量
int n, m;                       // 表示图中有n个点m条边
bool st[N];
int cnt;

// 链式前向星
int e[M], h[N], idx, w[M], ne[M];
void add(int a, int b, int c = 0) {
    e[idx] = b, ne[idx] = h[a], w[idx] = c, h[a] = idx++;
}
int main() {
#ifndef ONLINE_JUDGE
    freopen("in1.in", "r", stdin);
    // freopen("in2.in", "r", stdin);
#endif
    // 初始化链式前向星
    memset(h, -1, sizeof h);
    // 采用邻接表建图
    cin >> n >> m;
    // m条边
    for (int i = 1; i <= m; i++) {
        int a, b;
        cin >> a >> b;
        add(a, b);
    }
    // 利用bfs进行检查是不是强连通的
    // 把1号结点放入队列
    queue<int> q;
    q.push(1);

    while (q.size()) {
        int u = q.front();
        q.pop();
        st[u] = 1;
        cnt++;

        for (int i = h[u]; ~i; i = ne[i]) {
            int v = e[i];
            if (!st[v])
                q.push(v);
        }
    }

    if (cnt == n)
        printf("图是连通的\n");
    else
        printf("图不是连通的\n");
    return 0;
}

四、floyd

#include <bits/stdc++.h>

using namespace std;

const int N = 1010; // 图的最大点数量
int n, m;

// 用floyd来判断起点是否可以达到终点
int g[N][N]; // 邻接矩阵
void floyd() {
    for (int k = 1; k <= n; k++)
        for (int i = 1; i <= n; i++)
            for (int j = 1; j <= n; j++)
                g[i][j] = g[i][j] || (g[i][k] && g[k][j]);
}

int main() {
#ifndef ONLINE_JUDGE
    freopen("in1.in", "r", stdin);
    // freopen("in2.in", "r", stdin);
#endif

    // 采用邻接矩阵建图
    cin >> n >> m;
    // m条边
    for (int i = 1; i <= m; i++) {
        int a, b;
        cin >> a >> b;
        // 双向建边
        g[a][b] = 1, g[b][a] = 1;
    }
    // 调用floyd
    floyd();

    for (int i = 1; i <= n; i++)
        for (int j = 1; j <= n; j++)
            if (!g[i][j]) {
                printf("图不是连通的\n");
                cout << i << " " << j << endl;
                exit(0);
            }
    printf("图是连通的\n");
    return 0;
}