圖的連通性判斷(並查集+Bfs+Dfs+Floyd)
阿新 • • 發佈:2021-08-12
有向圖的連通性檢查共4種方法,並查集效能最高,程式碼也短,優先推薦:
一、並查集
#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 p; //詢問p對親戚關係 int x, y; //輸入兩個人之間的關係 int fa[N]; //並查集陣列 //要深入理解這個遞歸併壓縮的過程 int find(int x) { if (fa[x] != x)//如果x不是族長,遞迴找父親,副產品就是找回的結果更新掉自己的家族資訊。 fa[x] = find(fa[x]);//非常經典的更新,路徑壓縮大法! //返回族長是誰 return fa[x]; } //加入家族集合中 void join(int c1, int c2) { int f1 = find(c1), f2 = find(c2); if (f1 != f2)fa[f1] = f2;//各自找家長,如果家長不一樣,就把C1的族長,認C2的族長為爸爸,C1的族長強烈表示不滿意 } int cnt; int main() { //n個人員,m個關係 cin >> n >> m; //並查集初始化 for (int i = 1; i <= n; i++)fa[i] = i; //自己是自己的老大 //錄入m種關係,使用並查集來判斷圖的連通性 for (int i = 1; i <= m; i++) { cin >> x >> y; //加入並查集 join(x, y); } //圖已經搭好了,接下來看它們根節點是否相同,如只有一個相同的根節點,則說明是一個連通圖 for (int i = 1; i <= n; i++) if (fa[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; //圖的最大點數量 struct Edge { //記錄邊的終點,邊權的結構體 int to; //終點 int value; //邊權 }; int n, m; //表示圖中有n個點,m條邊 vector<Edge> p[N]; //使用vector的鄰接表 /** 共提供兩組資料,樣例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 檢測各種演算法是否能準確獲取結果 */ bool st[N]; int cnt; //深度遍歷 void dfs(int u) { st[u] = true; cnt++;//多走了一個結點 for (int i = 0; i < p[u].size(); i++) { int x = p[u][i].to; if (!st[x]) dfs(x); } } int main() { //採用鄰接表建圖 cin >> n >> m; //m條邊 for (int i = 1; i <= m; i++) { int u, v; cin >> u >> v; p[u].push_back({v, 1});//因本題不需要權值,預設權值為1 } //利用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; //圖的最大點數量 struct Edge { //記錄邊的終點,邊權的結構體 int to; //終點 int value; //邊權 }; int n, m; //表示圖中有n個點,m條邊 vector<Edge> p[N]; //使用vector的鄰接表 /** 共提供兩組資料,樣例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 檢測各種演算法是否能準確獲取結果 */ bool st[N]; int cnt; int main() { //採用鄰接表建圖 cin >> n >> m; //m條邊 for (int i = 1; i <= m; i++) { int u, v; cin >> u >> v; p[u].push_back({v, 1});//因本題不需要權值,預設權值為1 } //利用bfs進行檢查是不是強連通的 //把1號結點放入佇列 queue<int> q; q.push(1); while (!q.empty()) { int u = q.front(); q.pop(); st[u] = true; cnt++; for (int i = 0; i < p[u].size(); i++) { int x = p[u][i].to; if (!st[x]) q.push(x); } } 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;
/**
共提供兩組資料,樣例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
檢測各種演算法是否能準確獲取結果
*/
//用floyd來判斷起點是否可以達到終點
int dis[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++)
dis[i][j] = dis[i][j] || (dis[i][k] && dis[k][j]);
}
int main() {
//採用鄰接矩陣建圖
cin >> n >> m;
//m條邊
for (int i = 1; i <= m; i++) {
int u, v;
cin >> u >> v;
//雙向建邊
dis[u][v] = 1;
dis[v][u] = 1;
}
//呼叫floyd
floyd();
for (int i = 1; i <= n; i++)
for (int j = 1; j <= n; j++)
if (!dis[i][j]) {
printf("圖不是連通的\n");
cout << i << " " << j << endl;
exit(0);
}
printf("圖是連通的\n");
return 0;
}