連通圖的判斷(並查集, DFS, BFS)
阿新 • • 發佈:2018-11-08
首先要明確什麼是連通圖???
連通圖:對於一個圖來說,圖中的任意一個點都能訪問到所有的點,則說明該圖連通
很明顯,如果要判斷一個圖是否連通,則必須要從任意一個搜尋一遍,判斷是否到達了所有的點,則很快會想到DFS和BFS。但是用並查集去判斷是否連通,這種思想去確實沒有想到。
如果用並查集來判斷確實可以加快速度。讓自己對並查集又有了新的認識。同時並查集還可以判斷一個圖是否形成自迴路。
用一道題來說明連通圖的判斷:
給定一個無向圖和其中的所有邊,判斷這個圖是否所有頂點都是連通的。
輸入:每組資料的第一行是兩個整數n 和m(0< n <=1000)。n 表示圖的頂點
數目,m 表示圖中邊的數目。如果n 為0 表示輸入結束。隨後有m 行資料,每
行有兩個值x 和y(0<x, y <=n),表示頂點x 和y 相連,頂點的編號從1 開始計
算。輸入不保證這些邊是否重複。
輸出:對於每組輸入資料,如果所有頂點都是連通的,輸出 ’YES’ ,否則輸
出 ’NO’。
===樣例輸入===
4 3
1 2
2 3
3 2
3 2
1 2
2 3
0 0
===樣例輸出===
NOYES
並查集:首先任選一點,判斷他是否可以到達其他各點,利用路徑壓縮,使得並查集更高效。
以圖為例:
#include<cstdio> #include<iostream> #include<algorithm> #include<cstring> #include<string> #include<vector> using namespace std; const int maxn = 1e6+5; int pre[maxn]; int n, m; int find(int x){ if(pre[x] == x) return x; else return pre[x] = find(pre[x]); } int main() { for(int i = 1; i <= maxn; i++) pre[i] = i; scanf("%d%d", &n, &m); for(int i = 0; i < m; i++){ int u, v; scanf("%d%d", &u, &v); int fx = find(u), fy = find(v); pre[fx] = fy; } int cnt = 0; for(int i = 1; i <= n; i++){ if(pre[i] == i) cnt++; } if(cnt == 1) printf("Yes\n"); else printf("No\n"); return 0; }
用DFS進行搜尋,在搜尋的時候邊搜尋邊把已搜過的路刪掉
#include<cstdio> #include<iostream> #include<algorithm> #include<cstring> #include<string> #include<vector> using namespace std; const int maxn = 1e6+5; vector<int>G[maxn]; bool vis[maxn]; int n, m; void dfs(int x){ vis[x] = true; for(int i = 0; i < G[x].size(); i++){ if(vis[G[x][i]]) G[x].erase(G[x].begin() + i); else dfs(G[x][i]); } } bool pan(){ for(int i = 1; i <= n; i++){ if(!vis[i]){ return false; } } return true; } int main() { scanf("%d%d", &n, &m); for(int i = 0; i < m; i++){ int u, v; scanf("%d%d", &u, &v); G[u].push_back(v); G[v].push_back(u); } memset(vis, false, sizeof(vis)); dfs(1); //從第一個點開始搜 if(pan()) printf("Yes\n"); else printf("No\n"); return 0; }
用BFS進行遍歷,用到佇列,對這一部分還應加強學習
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
#include<string>
#include<queue>
#include<vector>
using namespace std;
const int maxn = 1e6+5;
vector<int>G[maxn];
int vis[maxn];
int n, m;
void bfs(int x){
queue<int>Q;
Q.push(x);
while(!Q.empty()){
int t = Q.front();
Q.pop();
vis[t] = true;
for(int i = 0; i < G[t].size(); i++){
if(vis[G[t][i]]) G[t].erase(G[t].begin() + i);
else Q.push(G[t][i]);
}
}
}
bool pan(){
for(int i = 1; i <= n; i++){
if(!vis[i]) return false;
}
return true;
}
int main()
{
scanf("%d%d", &n, &m);
for(int i = 0; i < m; i++){
int u, v;
scanf("%d%d", &u, &v);
G[u].push_back(v);
G[v].push_back(u);
}
memset(vis, false, sizeof(vis));
bfs(1);
if(pan()) printf("Yes\n");
else printf("No\n");
return 0;
}