图的连通性

图的连通性判断方法主要有:并查集、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 }
测试代码

猜你喜欢

转载自www.cnblogs.com/TianyuSu/p/9401017.html