Biểu diễn đồ thị và BFS tìm đường ngắn nhất
Biểu diễn đồ thị bằng danh sách kề, cài đặt BFS theo lớp và dùng nó tìm đường ngắn nhất trên đồ thị không trọng số.
Trung bìnhThuật toán ~60 phút
Ôn lại trước khi học
Giới thiệu
Bài này học biểu diễn đồ thị và thuật toán BFS. BFS này giúp tìm đường ít chặng nhất.
Kiến thức cần nhớ
Đồ thị và danh sách kề
- Đồ thị gồm đỉnh nối nhau bằng cạnh.
- Vô hướng như bạn bè, có hướng như theo dõi.
- Danh sách kề: mỗi đỉnh lưu tập đỉnh kề nó.
- Ví dụ đời thường: danh bạ lưu bạn của từng người.
BFS lan theo lớp
- Dùng hàng đợi FIFO: vào trước xét trước.
- Cần tập đã thăm để tránh quay vòng.
- Thăm hết lớp gần rồi mới sang lớp xa.
- Ví dụ đời thường: sóng nước lan tròn từ tâm.
# BFS: hàng đợi + tập đã thăm
from collections import deque
def bfs(graph, start):
tham = {start} # đánh dấu đã thăm
q = deque([start]) # hàng đợi lớp hiện tại
while q: # còn nút là còn lan
u = q.popleft() # lấy đầu hàng
for v in graph[u]: # xét từng lân cận
if v not in tham: # chưa thăm
tham.add(v) # đánh dấu
q.append(v) # xếp cuối hàng
return tham
Vì sao ra đường ngắn nhất
- Lớp gần được xét trước nên chạm trước là gần nhất.
- Muốn đường cụ thể thì lưu thêm cha mỗi nút.
- Thời gian tuyến tính theo đỉnh cộng cạnh.
- Ví dụ đời thường: tìm bạn chung 1 cầu trước khi tìm 2 cầu.
Ví dụ
- Input: mạng 6 người, BFS từ Amin -> Output: thăm đủ 6 người theo lớp.
- Câu này cho thấy sóng lan lớp 1, lớp 2, lớp 3.
- Input: đồ thị 2 vùng rời, BFS từ vùng 1 -> Output: chỉ thăm vùng 1.
- Câu này cho thấy BFS không bay qua vùng rời.
💻 Bài tập
Ngôn ngữ: C++. Nộp vào day-040/.
Bài 1: Đồ thị danh sách kề
class Graph {
public:
Graph(int n, bool directed);
void addEdge(int u, int v);
const std::vector<int> &neighbors(int u) const;
int n() const;
static Graph fromFile(const std::string &path); // dòng đầu "n m directed", m dòng "u v"
};
Viết thêm std::vector<std::vector<bool>> toMatrix(). Ghi vào README.md bộ nhớ của 2 cách lưu với , .
Bài 2: BFS và đường đi ngắn nhất
| Hàm | Yêu cầu |
|---|---|
std::vector<int> bfsDist(const Graph&, int s) | Khoảng cách theo số cạnh, không tới được là -1 |
std::vector<int> bfsParent(const Graph&, int s) | Cha trên cây BFS |
std::vector<int> shortestPath(const Graph&, int s, int t) | Dãy đỉnh từ s tới t, không có đường thì rỗng |
int components(const Graph&) | Số thành phần liên thông (đồ thị vô hướng) |
Cạnh vô hướng: 0-1, 0-2, 1-3, 2-3, 3-4, 5-6
bfsDist(0) -> [0,1,1,2,3,-1,-1]
shortestPath(0, 4) -> [0,1,3,4]
shortestPath(0, 6) -> []
components -> 2
Độ phức tạp phải là .
Bài 3: BFS trên lưới (nâng cao)
- Mê cung đọc từ file,
#là tường,Sbắt đầu,Ekết thúc. In độ dài đường ngắn nhất và vẽ đường đi bằng*. - Multi-source BFS: lưới có nhiều ô
Flà đám cháy. Tính mỗi ô cách đám cháy gần nhất bao nhiêu bước. - Bipartite: kiểm tra đồ thị có tô được 2 màu không bằng BFS.
S . . #
# # . #
. . . E -> độ dài 5
✅ Tiêu chí hoàn thành
- Test mẫu pass.
-
shortestPathdựng lại đường từ mảng cha đúng. - Bài 3 in mê cung có vẽ đường.
- Chứng minh bằng lời vì sao BFS cho đường ngắn nhất trên đồ thị không trọng số.
❓ Câu hỏi ôn tập
- Danh sách kề lưu đồ thị thế nào?
- BFS dùng cấu trúc gì để lan lớp?
- Vì sao cần tập đã thăm?
- Khi nào BFS không còn đúng nữa?
🌕 Bạn đã hoàn thành ngày 40. Làm hết bài tập phía trên rồi sang ngày tiếp theo.