zoukankan      html  css  js  c++  java
  • 图的连通性

    图的连通性判断方法主要有:并查集、DFS、BFS、WARSHALL

    一、并查集

    使用并查集维护所有边,如果 parent 数组中只有一个 根节点 那么,此图是联通图。

    若不是一个根节点,那么连通分支数为 根节点个数

    代码:

     1 int parent[maxn];
     2 int find_root (int n) {
     3     return parent[n] == -1 ? n : parent[n] = find_root(parent[n]);
     4 }
     5 
     6 
     7 //连通分支数 = parent 中 -1 个数
     8 bool union_solve() {
     9     memset(parent, -1, sizeof(parent));
    10     for (int i = 0; i < n; i++) {
    11         for (int j = 0; j < n; j++) {
    12             if (mapp[i][j]) {
    13                 int r1 = find_root(i), r2 = find_root(j);
    14                 if (r1 != r2)
    15                     parent[j] = r1;
    16             }
    17         }
    18     }
    19 
    20     //如果parent 中只有一个 根节点 那么就连通
    21     int cnt = 0;
    22     for (int i = 0; i < n; i++)
    23         if (parent[i] == -1)
    24             cnt++;
    25     return cnt == 1 ? true : false;
    26 }

    二、DFS

    如果 vis 数组都是 true 说明是一个连通图. 否则 连通分支数 = 对图中所有点进行 dfs,运行了几次,说明就有几个连通分支数

    代码:

     1 bool vis[maxn];
     2 void dfs(int x) {
     3     vis[x] = true;
     4     for (int i = 0; i < n; i++) {
     5         if (mapp[x][i] && !vis[i])
     6             dfs(i);
     7     }
     8 }
     9 
    11 bool dfs_solve() {
    12     memset(vis, 0, sizeof(vis));
    13     dfs(0);
    14     for (int i = 0; i < n; i++)
    15         if (!vis[i])
    16             return false;
    17     return true;
    18 }

    三、BFS

    如果 cnt 等于 n 那么就是一个连通图,否则连通分支数 = 对图中所有点进行 dfs,运行了几次,说明就有几个连通分支数

    代码:

     1 bool bfs_solve() {
     2     int cnt = 0;
     3     memset(vis, 0, sizeof(vis));
     4     queue<int> q;
     5     q.push(0);
     6     while (!q.empty()) {
     7         int x = q.front(); q.pop();
     8         vis[x] = true;
     9         cnt++;
    10         for (int i = 0; i < n; i++)
    11             if (mapp[x][i] && !vis[i]) {
    12                 q.push(i);
    13                 vis[i] = true;    //保证cnt==n时访问全部点,防止一个节点被加入队列两次
    14             }
    15     }
    16     return cnt == n;
    17 }

    四、WARSHALL 算法

    这个算法主要是利用求解传递闭包的思想,如果图是连通图那么 这个连通矩阵是一个 全1 矩阵。如果不是连通图,那么在主对角线上,有几个 全1 矩阵那么就是几个连通分支

    例如:

    1. 连通图的连通矩阵为,例如 4 个点

    1 1 1 1

    1 1 1 1

    1 1 1 1

    1 1 1 1

    2. 两个连通分支 连通矩阵为: 例如 4 个点

    1 1 0 0

    1 1 0 0

    0 0 1 1

    0 0 1 1

    代码:

     1 bool warshall_solve() {
     2     for (int k = 0; k < n; k++) {
     3         for (int i = 0; i < n; i++) {
     4             for (int j = 0; j < n; j++)
     5                 mapp[i][j] = mapp[i][j] || (mapp[i][k] && mapp[k][j]);
     6             mapp[i][i] = 1; //自己和自己连通
     7         }
     8     }
     9 
    10     //矩阵中全为 1, 即表示连通图
    11     for (int i = 0; i < n; i++)
    12         for (int j = 0; j < n; j++)
    13             if (!mapp[i][j])
    14                 return false;
    15     return true;
    16 }

    五、测试代码:

      1 #include <algorithm>
      2 #include <cstdio>
      3 #include <cstring>
      4 #include <string>
      5 #include <cmath>
      6 #include <iostream>
      7 #include <map>
      8 #include <queue>
      9 #include <set>
     10 #include <vector>
     11 
     12 using namespace std;
     13 
     14 
     15 #define max3(x, y, z) max(max((x), (y)), (z))
     16 #define min3(x, y, z) min(mix((x), (y)), (z))
     17 #define pb push_back
     18 #define ppb pop_back
     19 #define mk make_pair
     20 #define pii pair<int, int>
     21 #define pll pair<long long, long long>
     22 
     23 
     24 #define debug_l(a) cout << #a << " " << (a) << endl
     25 #define debug_b(a) cout << #a << " " << (a) << " "
     26 #define testin(filename) freopen((filename) ,"r",stdin)
     27 #define testout(filename) freopen((filename) ,"w",stdout)
     28 
     29 
     30 #define close_sync (ios::sync_with_stdio(false))
     31 
     32 
     33 
     34 typedef long long ll;
     35 typedef unsigned long long ull;
     36 
     37 
     38 const double PI  = 3.14159265358979323846264338327;
     39 const double E   = exp(1);
     40 const double eps = 1e-6;
     41 
     42 const int INF    = 0x3f3f3f3f;
     43 const int NINF   = 0xc0c0c0c0;
     44 // int maxn   = 3e3 + 5;
     45 // int MOD    = 1e9 + 7;
     46 
     47 
     48 template <typename T>
     49 void print_arr(T *arr, int arr_len)
     50 {
     51     for (int i = 0; i < arr_len; i++)
     52         cout << arr[i] << " ";
     53     cout << endl;
     54 }
     55 
     56 const int maxn = 1e3 + 5;
     57 //存图
     58 int mapp[maxn][maxn];
     59 int n, m; //定点数,边数
     60 
     61 
     62 int parent[maxn];
     63 int find_root (int n) {
     64     return parent[n] == -1 ? n : parent[n] = find_root(parent[n]);
     65 }
     66 
     67 
     68 //连通分支数 = parent 中 -1 个数
     69 bool union_solve() {
     70     memset(parent, -1, sizeof(parent));
     71     for (int i = 0; i < n; i++) {
     72         for (int j = 0; j < n; j++) {
     73             if (mapp[i][j]) {
     74                 int r1 = find_root(i), r2 = find_root(j);
     75                 if (r1 != r2)
     76                     parent[j] = r1;
     77             }
     78         }
     79     }
     80 
     81     //如果parent 中只有一个 根节点 那么就连通
     82     int cnt = 0;
     83     for (int i = 0; i < n; i++)
     84         if (parent[i] == -1)
     85             cnt++;
     86     return cnt == 1 ? true : false;
     87 }
     88 
     89 
     90 
     91 
     92 bool vis[maxn];
     93 void dfs(int x) {
     94     vis[x] = true;
     95     for (int i = 0; i < n; i++) {
     96         if (mapp[x][i] && !vis[i])
     97             dfs(i);
     98     }
     99 }
    100 
    101 //连通分支数 = 对图中所有点进行 dfs,运行了几次,说明就有几个连通分支数
    102 bool dfs_solve() {
    103     memset(vis, 0, sizeof(vis));
    104     dfs(0);
    105     for (int i = 0; i < n; i++)
    106         if (!vis[i])
    107             return false;
    108     return true;
    109 }
    110 
    111 
    112 //连通分支数 = 对图中所有点进行 bfs,运行了几次,说明就有几个连通分支数
    113 bool bfs_solve() {
    114     int cnt = 0;
    115     memset(vis, 0, sizeof(vis));
    116     queue<int> q;
    117     q.push(0);
    118     while (!q.empty()) {
    119         int x = q.front(); q.pop();
    120         vis[x] = true;
    121         cnt++;
    122         for (int i = 0; i < n; i++)
    123             if (mapp[x][i] && !vis[i]) {
    124                 q.push(i);
    125                 vis[i] = true;    //保证cnt==n时访问全部点,防止一个节点被加入队列两次
    126             }
    127     }
    128     return cnt == n;
    129 }
    130 
    131 
    132 //连通分支数为主对角线上 单位阵的个数
    133 // 利用传递闭包求解
    134 bool warshall_solve() {
    135     for (int k = 0; k < n; k++) {
    136         for (int i = 0; i < n; i++) {
    137             for (int j = 0; j < n; j++)
    138                 mapp[i][j] = mapp[i][j] || (mapp[i][k] && mapp[k][j]);
    139             mapp[i][i] = 1; //自己和自己连通
    140         }
    141     }
    142 
    143 
    144     for (int i = 0; i < n; i++) {
    145         print_arr(mapp[i], n);
    146         cout << endl;
    147     }
    148 
    149     //矩阵中全为 1, 即表示连通图
    150     for (int i = 0; i < n; i++)
    151         for (int j = 0; j < n; j++)
    152             if (!mapp[i][j])
    153                 return false;
    154     return true;
    155 }
    156 
    157 
    158 
    159 //读入图,假定为无向图
    160 void input() {
    161     memset(mapp, 0, sizeof(mapp));
    162     cout << "输入顶点数、边数:";
    163     cin >> n >> m;
    164     cout << "输入(u,v) 代表有一条边,编号从1开始" << endl;
    165     int u, v;
    166     for (int i = 0; i < m; i++) {
    167         cin >> u >> v;
    168         mapp[u - 1][v - 1] = mapp[v - 1][u - 1] = 1;
    169     }
    170 }
    171 
    172 int main(int argc, char const *argv[])
    173 {
    174 
    175     //testin("../data.in");
    176     input();
    177     debug_l(union_solve());
    178     debug_l(dfs_solve());
    179     debug_l(bfs_solve());
    180     debug_l(warshall_solve());
    181     return 0;
    182 }
    测试代码
  • 相关阅读:
    动态第K大 (树状数组套主席树)
    AC自动机
    开发Jquery插件文字自动截取(提供源代码)
    基于CentOS 5.5,集成LAMP、LNMP精简定制版应用服务器
    MySQL中的mysqldump命令使用详解
    开源CRM和ERP撑起后台系统能走多远
    squid,正向代理,反向代理
    linux架设subversion(svn)版本控制
    浅谈php的urlencode()函数
    读《MYSQL开发者SQL权威指南》笔记
  • 原文地址:https://www.cnblogs.com/TianyuSu/p/9401017.html
Copyright © 2011-2022 走看看