Professional Documents
Culture Documents
Chủ đề:
Thuật toán BFS và bài toán duyệt tất cả các thành
phần liên thông của đồ thị
Hà Nội 2022
I. THUẬT TOÁN TÌM KIẾM THEO CHIỀU RỘNG (BFS)
- Thuật toán duyệt đồ thị ưu tiên chiều rộng (Breadth-first search – BFS) là một
trong những thuật toán tìm kiếm cơ bản và thiết yếu trên đồ thị. Mà trong đó
những đỉnh nào gần đỉnh xuất phát hơn sẽ được duyệt trước.
- Ứng dụng của BFS có thể giúp ta giải quyết tốt một số bài toán trong thời gian
và không gian tối thiểu. Đặc biệt là bài toán tìm kiếm đường đi ngắn nhất từ một
đỉnh gốc tới tất cả các đỉnh khác. Trong đồ thị không có trọng số tất cả trọng số
bằng nhau, thuật toán sẽ luôn trả ra đường đi ngắn nhất có thể. Ngoài ra, thuật
toán này còn được dù để tìm các thành phần liên thông của đồ thị, hoặc kiểm tra
đồ thị hai phía,…
II. Mô tả thuật toán BFS
Đầu tiên ta thăm đỉnh nguồn ss.
Ví dụ: Cho đồ thị G = <V,E>, trình bày quá trình thuật toán BFS bắt đầu
chạy từ đỉnh 1
STT Trạng thái Queue Các đỉnh được duyệt
1 1 Ø
2 2,3,5,10 1
3 3,4,5,10 1,2
4 5,10,4,6,7,9 1,2,3
5 10,4,6,7,9,8 1,2,3,5
6 4,6,7,9,8 1,2,3,5,10
7 6,7,9,8 1,2,3,5,10,4
8 7,9,8 1,2,3,5,10,4,6
9 9,8 1,2,3,5,10,4,6,7
10 8 1,2,3,5,10,4,6,7,9
11 Ø 1,2,3,5,10,4,6,7,9,8
IV. THUẬT TOÁN BFS DUYỆT TẤT CÁC THÀNH PHẦN LIÊN
THÔNG CỦA ĐỒ THỊ
1. Đếm số thành phần liên thông của đồ thị vô hướng
- Nếu đồ thị là liên thông thì số thành phần liên thông của nó là 1. Tương ứng
với thủ tục BFS(u) được gọi đúng 1 lần.
- Nếu đồ thị không liên thông thì số thành phần không liên thông của nó >1. Suy
ra có thể xác định số thành phần liên thông bằng cách gọi hàm BFS.
- Thuật toán xác định số thành phần liên thông của đồ thị.
Mã giả
Số TPLT(){
//Khởi tạo số TPLT ban đầu của đồ thị = 0
cnt = 0;
//Lặp
for(int i = 1; i <= n; i++) //Duyệt tất cả các đỉnh
if(!visited[i]){
++cnt; //Tăng số thành phần liên thông
BFS(i);
}
}
return cnt;
}
Ví dụ: Cho ma trận kề của đồ thị có hướng G= <V, E>. Xác định xem G có
liên thông mạnh hay không?
1 2 3 4 5 6 7 8 9 10 11 12 13
1 0 0 0 0 0 1 0 0 0 0 0 0 0
2 0 0 1 0 0 0 0 1 0 0 0 0 0
3 0 0 0 0 0 0 0 0 1 0 0 0 1
4 1 0 0 0 0 1 0 0 0 0 0 0 0
5 0 0 0 0 0 0 1 0 0 0 0 0 0
6 0 0 0 0 0 0 0 0 0 1 0 1 0
7 0 0 0 0 0 0 0 0 0 0 1 0 1
8 0 0 0 1 0 0 0 0 0 0 0 1 0
9 0 0 0 0 1 0 1 0 0 0 0 0 0
10 0 1 1 0 0 0 0 0 0 0 0 0 0
11 0 1 0 0 0 0 0 1 0 0 0 0 0
12 0 0 0 1 0 0 0 0 0 1 0 0 0
13 0 0 0 0 0 0 0 0 1 0 1 0 0
-Ta thấy cột ngoài cùng của bảng BFS(u) = V ∀ u ∈V nên kết luận G là liên
thông mạnh. Nếu 1 hàng nào đó có BFS(u) ≠ V ta kết luận đồ thị không liên
thông mạnh
V. Phần code ứng dụng của BFS để đếm số thành phần liên thông
của đồ thị và chỉ ra những thành phần liên thông
-Đề bài: Cho danh sách cạnh của đồ thị vô hướng G = <n, m >. Xác định
xem G có liên thông hay không và chỉ ra các thành phần liên thông của G.
- Danh sách cạnh (input)
10 8 // 10 là số đỉnh, 8 là số cạnh
12
23
24
36
37
67
58
89
Code
#include<bits/stdc++.h>
using namespace std;
// Duyệt tất cả các thành phần liên thông của đồ thị.
int n, m; // n là số lượng đỉnh , m là số lượng cạnh.
vector<int> adj[1001]; // vector adj để lưu danh sách kề của G = (n, m).
bool visited[1001]; // mảng visited dùng để đánh dấu các đỉnh đã được
thăm.
void nhap(){
memset(visited, false, sizeof(visited));
cin >> n >> m;
for(int i = 1; i <= m; i++){
int x, y; cin >> x >> y;
adj[x].push_back(y);
adj[y].push_back(x);
}
}
void connectedComponent(){
int ans = 0; // Khởi tạo số TPLT của đồ thị.
for(int i = 1; i <= n; i++){
if(!visited[i]){
++ans;
cout << "Cac dinh thuoc thanh phan lien thong thu " <<
ans << " :\n";
BFS(i);
cout << endl;
}
}
if(ans == 1)
cout << "Do thi lien thong !\n";
else
cout << "Do thi khong lien thong !\n";
}
Out put:
Cac dinh thuoc thanh phan lien thong thu 1 :
123467
Cac dinh thuoc thanh phan lien thong thu 2 :
589
Cac dinh thuoc thanh phan lien thong thu 3 :
10
Do thi khong lien thong !