Bài toán tìm hai đường đi sao cho không có cạnh nào chung và có tổng độ dài ngắn nhất trong Lý thuyết đồ thị là bài toán có ứng dụng cao trong thực tế.. Phần II: Giải quyết bài toán Trìn
Trang 1KHOA CÔNG NGHỆ THÔNG TIN
-O0O -BÀI TẬP MÔN
PHÂN TÍCH VÀ ĐÁNH GIÁ THUẬT TOÁN
Giáo viên hướng dẫn: PGS TS Đào Thanh Tĩnh
Người thực hiện: Phạm Phương Duy
Lớp: Cao học CNTT – khóa K25
Trang 3LỜI NÓI ĐẦU 1
Phần I GIỚI THIỆU BÀI TOÁN 1 Bài toán đặt ra 3
2 Mô tả dữ liệu vào/ra của bài toán 3
2.1 Dữ liệu vào 3
2.2 Dữ liệu ra 4
Phần 2 GIẢI QUYẾT BÀI TOÁN 1 Khái niệm cơ bản về đồ thị 5
1.1 Định nghĩa đồ thị (Graph) 5
1.2 Biểu diễn đồ thị trên máy tính 6
1.3 Dây chuyền, chu trình, đường đi và Mạch 8
2 Thuật toán tìm đường đi ngắn nhất Dijkstra 9
3 Thuật toán duyệt các đỉnh của đồ thị theo theo chiều sâu 12
4 Kết hợp thuật toán Dijsktra và tìm kiếm theo chiều sâu để giải quyết bài toán đặt ra 12
TÀI LIỆU THAM KHẢO 15
Trang 4LỜI NÓI ĐẦU
Trên thực tế có nhiều bài toán liên quan tới một tập các đối tượng và những mối liên hệ giữa chúng, đòi hỏi toán học phải đặt ra một mô hình biểu diễn một cách chặt chẽ và tổng quát bằng ngôn ngữ ký hiệu, đó là đồ thị Những ý tưởng cơ bản của nó được đưa ra từ thế kỷ thứ XVIII bởi nhà toán học Thụy Sĩ Leonhard Euler, ông đã dùng mô hình đồ thị để giải bài toán về những cây cầu Konigsberg nổi tiếng
Mặc dù Lý thuyết đồ thị đã được khoa học phát triển từ rất lâu nhưng lại có nhiều ứng dụng hiện đại Đặc biệt trong khoảng vài mươi năm trở lại đây, cùng với
sự ra đời của máy tính điện tử và sự phát triển nhanh chóng của Tin học, Lý thuyết
đồ thị càng được quan tâm đến nhiều hơn Đặc biệt là các thuật toán trên đồ thị đã
có nhiều ứng dụng trong nhiều lĩnh vực khác nhau như: Mạng máy tính, Lý thuyết
mã, Tối ưu hóa, Kinh tế học,… Chẳng hạn như trả lời câu hỏi: Hai máy tính trong mạng có thể liên hệ được với nhau hay không?; hay vấn đề phân biệt hai hợp chất hóa học có cùng công thức phân tử nhưng lại khác nhau về công thức cấu tạo cũng được giải quyết nhờ mô hình đồ thị
Bài toán tìm hai đường đi sao cho không có cạnh nào chung và có tổng độ dài ngắn nhất trong Lý thuyết đồ thị là bài toán có ứng dụng cao trong thực tế Vì vậy, em chọn đề bài này để nghiên cứu
Cấu trúc của báo cáo được chia thành hai phần:
Phần I: Giới thiệu bài toán
Trình bày bài toán đặt ra và mô tả dữ liệu vào ra của bài toán
Phần II: Giải quyết bài toán
Trình bày những khái niệm cơ bản liên quan đến đồ thị và thuật toán tìm đường đi ngắn nhất Dijkstra và thuật toán tìm đường đi theo chiều sâu Từ đó kết hợp hai thuật toán để giải quyết bài toán đặt ra của báo cáo
Trang 5Để hoàn thành báo cáo này trước hết chúng em xin chân trọng tỏ lòng biết ơn tới PGS TS Đào Thanh Tĩnh - người đã trực tiếp giảng dạy môn học Phân tích và Đánh giá thuật toán với cách thức truyền đạt hết sức khoa học và nghiêm túc Chúng tôi cũng xin chân thành cảm ơn các bạn bè và đồng nghiệp đã nhiệt tình giúp đỡ và chỉ bảo, vì còn hạn chế về nhiều mặt nên báo cáo không tránh khỏi những thiếu sót, rất mong được Thầy cùng các bạn nhận xét và góp ý để chúng tôi hoàn thiện báo cáo hơn nữa
Trang 6Phần I GIỚI THIỆU BÀI TOÁN
1 Bài toán đặt ra
Cho đồ thị vô hướng G ={V, E} được cho bởi danh sách cạnh DS Cho u, v
V Xây dựng thuật toán tìm hai đường đi (u,v) và (u,v) sao cho không có cạnh nào chung và có tổng độ dài ngắn nhất
Phát biểu lại bài toán:
- Có đồ thị vô hướng G gồm n đỉnh và m cạnh được cho bởi danh sách cạnh
như sau:
Canh = Record d,c: Tên đỉnh;
Length: Độ dài đường đi;
End;
Ds[1 m] Of Canh;
- Yêu cầu: Tìm hai đường đi (u,v) và (u,v) sao cho không có cạnh nào chung và có tổng độ dài ngắn nhất
2 Mô tả dữ liệu vào/ra của bài toán
2.1 Dữ liệu vào
Từ file văn bản “dulieuvao.inp” có cấu trúc như sau:
+ Dòng thứ nhất ghi 4 số nguyên dương cách nhau một dấu cách lần lượt là:
- n là số đỉnh của đồ thị G;
- m là số cạnh của đồ thị G;
- u đỉnh xuất phát;
- v đỉnh đích.
+ Dòng thứ i trong số m dòng tiếp theo ghi ba số cách nhau một dấu lần lượt là:
3
Trang 7- d là đỉnh đầu của một cạnh;
- c là đỉnh cuối của một cạnh;
- Length là độ dài của cạnh (đường đi).
2.2 Dữ liệu ra
Được ghi vào file văn bản “dulieura.out” có cấu trúc như sau:
+ Dòng thứ nhất ghi đường đi (u,v);
+ Dòng thứ hai ghi đường đi (u,v);
+ Dòng thứ ba tổng độ dài ngắn nhất của hai đường đi;
4
Trang 8Phần II GIẢI QUYẾT BÀI TOÁN
1 Khái niệm cơ bản về đồ thị
1.1 Định nghĩa đồ thị (Graph)
Là một cấu trúc rời rạc gồm các đỉnh và các cạnh nối các đỉnh đó Được mô
tả hình thức:
G=(V,E)
V gọi là tập các đỉnh (Vertices) và E gọi là tập các cạnh (Edges) Có thể coi
E là tập các cặp (u, v) với u và v là hai đỉnh của V
Một số hình ảnh của đồ thị:
Có thể phân loại đồ thị theo đặc tính và số lượng của tập các cạnh E:
Cho đồ thị G=(V, E) Định nghĩa một cách hình thức
1 G được gọi là đơn đồ thị nếu giữa hai đỉnh u, v của V có nhiều nhất là 1
cạnh trong E nối từ u tới v
2 G được gọi là đa đồ thị nếu giữa hai đỉnh u, v của V có thể có nhiều hơn 1
cạnh trong E nối từ u tới v (Hiển nhiên đơn đồ thị cũng là đa đồ thị)
3 G được gọi là đồ thị vô hướng nếu các cạnh trong E là không định hướng,
tức là cạnh nối hai đỉnh u, v bất kỳ cũng là cạnh nối hai đỉnh u, v Hay nói cách khác, tập E gồm các cặp (u, v) không tính thứ tự (u,v) (v,u)
5
Trang 94 G được gọi là đồ thị có hướng nếu các cạnh trong E là có định hướng, có
thể có cạnh nối từ đỉnh u tới đỉnh v nhưng chưa chắc đã có cạnh nối từ đỉnh v tới đỉnh u Hay nói cách khác, tập E gồm các cặp (u, v) có tính thứ tự: (u,v) (v,u)
Trong đồ thị có hướng, các cạnh được gọi là các cung Đồ thị vô hướng cũng
có thể coi là đồ thị có hướng nếu như ta coi cạnh nối hai đỉnh u, v bất kỳ tương đương với hai cung (u, v) và (v, u)
Ví dụ:
1.2 Biểu diễn đồ thị trên máy tính
1.2.1 Ma trận kiền kề (Ma trận kề)
Giả sử G=(V, E) là một đơn đồ thị có số đỉnh (ký hiệu V ) là n Không mất tính tổng quát có thể coi các đỉnh được đánh số 1, 2,…, n Khi đó ta có thể biểu diễn đồ thị bằng một ma trận vuông A a ij cấp n Trong đó:
a ij 1 nếu i, jE
a ij 0 nếu i, jE
Quy ước a ii 0 với i;
Đối với đa đồ thị thì việc biểu diễn cũng tương tự trên, chỉ có điều nếu như (i, j) là cạnh thì không phải ta ghi số 1 vào vị trí a ij mà là ghi số cạnh nối giữa đỉnh i và đỉnh j
6
Trang 101.2.2 Danh sách cạnh
Trong trường hợp đồ thị có n đỉnh, m cạnh, ta có theerbieeur diễn đồ thị dưới dạng danh sách cạnh, trong cách biểu diễn này, người ta liệt kê tất cả các cạnh của đồ thị trong một danh sách, mỗi phần tử của danh sách là một cặp (u, v) tương ứng với một cạnh của đồ thị (Trong trường hợp đồ thị có hướng thì mỗi cặp (u, v) tương ứng với một cung, u là đỉnh đầu và v là đỉnh cuối của cung) Danh sách được lưu trong bộ nhớ dưới dạng mảng hoặc danh sách móc nối Ví dụ với đồ thị dưới đây:
7
Trang 11Ưu điểm của danh sách cạnh:
Trong trường hợp đồ thị thưa (có số cạnh tương đối nhỏ: chẳng hạn m < 6n), cách biểu diễn bằng danh sách cạnh sẽ tiết kiệm được không gian lưu trữ, bởi
nó chỉ cần 2m ô nhớ để lưu danh sách cạnh
Trong một số trường hợp, ta phải xét tất cả các cạnh của đồ thị thì cài đặt danh sách cạnh làm cho việc duyệt các cạnh dễ dàng hơn (Thuật toán Kruskal chẳng hạn)
Nhược điểm của danh sách cạnh:
Nhược điểm cơ bản của danh sách cạnh là khi ta cần duyệt tất cả các đỉnh
kề với đỉnh v nào đó của đồ thị, thì chẳng có cách nào khác là phải duyệt tất cả các cạnh, lọc ra những cạnh đó chứa đỉnh v và xét đỉnh còn lại Điều đó khá tốn thời gian trong trường hợp đồ thị dày (nhiều cạnh)
1.3 Dây chuyền, chu trình, đường đi và Mạch
Cho đồ thị G=(V,E)
Dây chuyển: Một day chuyền trong G là một dãy luân phiên các đỉnh và
cạnh: v1e1v2e2v m1e m1v m (v i là đỉnh và e i là cạnh)
Trong đồ thị thỏa mãn điều kiện e i liên kết với cặp đỉnh v i,v i1 không phân biệt thứ tự, nghĩa là:
, 1
i i
i v v
e hay e i v i1,v i nếu đồ thị có hướng,
, 1
i i
i v v
e nếu đồ thị vô hướng
Khi đó ta gọi v1 là đỉnh đầu và v là đỉnh cuối của dây chuyền m
Dây chuyền sơ cấp: Dây chuyền không có đỉnh lặp lại.
Chu trình: Là một dây chuyền v1e1v2e2 v m1e m1v m e m v1 sao cho các đỉnh
m
v
v
v1, 2, , đôi một khác nhau
Đường đi: Một đường đi trong G là một dãy luân phiên các đỉnh và cạnh:
m m
m e v v
e v e
v1 1 2 2 1 1 (v i là đỉnh và e i là cạnh) trong đồ thị thỏa mãn điều kiện e i liên kết với cặp đỉnh v i,v i1, nghĩa là:
8
Trang 12e liên kết với v i,v i1 nếu đồ thị có hướng,
i
e liên kết với v i,v i1 nếu đồ thị vô hướng
Khi đó ta gọi v1 là đỉnh đầu và v là đỉnh cuối của đường đi m
Đường đi sơ cấp: Đường đi không có đỉnh lặp lại.
Mạch: Là một đường đi v1e1v2e2 v m1e m1v m e m v1 sao cho các đỉnh
m
v
v
v1, 2, , đôi một khác nhau
2 Thuật toán tìm đường đi ngắn nhất Dijkstra
Xét đồ thị G=(V,E) có trọng với V 1 , 2 , ,n và giả sử các cạnh không âm
- Dữ liệu nhập cho thuật toán là ma trận trọng lượng L (với qui ước L hk
nếu không có cạnh nối từ đỉnh h đến đỉnh k) và hai đỉnh i, j cho trước
- Dữ liệu xuất là đường đi ngắn nhất từ i đến j
Bước 1: Gán T:= V và gắn các nhãn:
Dodai[i]=0; Dodai[k]=, kV \ i ;
Nhan[k]= -1, k V Bước 2: Nếu j T thì dừng và giá trị Dodai[j] chính là độ dài đường đi ngắn nhất từ i đến j và Nha[j] là đỉnh nằm ngay trước j trên đường đi đó
Bước 3: Chọn đỉnh v T sao cho Dodai[v] nhỏ nhất và gán T :T \ v Bước 4: Với mọi đỉnh k T và có cạnh nối từ v đến k,
nếu Dodai[k] > Dodai[v] + L vk thì Dodai[k] = Dodai[v] + L vk và Nha[k] = v
Trở về bước 2
Ghi chú: Khi thuật toán dừng, nếu Dodai[j]= thì không tồn tại đường đi từ i đến j, nếu ngược lại thì Dodai[j] là độ dài đường đi ngắn nhất và ta lần ngược ra đường đi ngắn nhất (đi ngược từ j trờ về lại i) như sau:
write(j);
k:= Nhan[j];
while k<>i Do
9
Trang 13write(‘< ‘, k);
K:= Nhan[k];
End;
write(‘< ‘, i);
Ví dụ: Áp dụng thuật toán Dijkstra, tìm đường đi ngắn nhất giữa đỉnh k đến đỉnh e, với dữ liệu đồ thị G có hướng, liên thông được cho bởi danh sách cạnh sau:
1) a b 5 9) b c 2 17) d c 6 25) h f 5 2) f e 2 10) a f 6 18) i d 6 26) h d 5 3) g h 2 11) f g 6 19) j i 6 27) e g 3 4) m k 2 12) g m 6 20) a e 1 28) j h 2 5) k j 1 13) e b 3 21) m h 6 28) k i 5 6) h i 1 14) g k 5 22) f b 5
7) i e 2 15) h e 4 23) e c 2 8) e d 1 16) k h 4 24) d b 5
Giải
- Từ dữ liệu về đồ thị ta có danh sách kề sau:
a b, f, e
a, e, f, d b c
b, d, e c
e, i, h d c, b
f, i, h, a e d, b, c, g
a, h f e, g, b
f, e g h, m, k
g, k, m,
j
h i, e, f, d
h, j, k i e, d
m, g k j, h, i
g m k, h
k j i, h
- Ta dùng bảng dưới đây để tìm đường đi ngắn nhất từ đỉnh k đến đỉnh e:
đang xét
10
Trang 141 k 0 k
e
Từ bảng trên ta có độ dài đường đi từ k tới e là 6 Xác định đường đi:
1) u0 = e;
2) V-(e) = {f, i, h, a} ; L(e) = 6;
L(f)= 5; F(f,e) = 2; L(f) + F(f,e) = 5 + 2 = 7 > 6 = L(e)
L(i)= 4; F(i,e) = 2; L(i) + F(i,e) = 4 + 2 = 6 = 6 = L(e)
L(h)= 3; F(h,e) = 4; L(h) + F(h,e) = 3 + 4 = 7 > 6 = L(e)
L(a)= ; F(a,e) = 1; L(a) + F(a,e) = + 1 = > 6 = L(e)
Vậy u1 = i;
2) V-(i) = {h, j, k}
L(h)= 3; F(h,i) = 1; L(h) + F(h,i) = 3 + 1 = 4 = 4 = L(i)
L(j)= 1; F(j,i) = 6; L(j) + F(j,i) = 1 + 6 = 7 > 4 = L(i)
L(k)= 0; F(k,i) = 5; L(k) + F(k,i) = 0 + 5 = 5 > 4 = L(i)
Vậy u2 = h;
3) V-(h) = {g, k, m, j}
L(g)= 9; F(g,h) = 2; L(g) + F(g,h) = 9 + 2 = 11 > 3 = L(h)
L(k)= 0; F(k,h) = 4; L(k) + F(k,h) = 0 +4 = 4 > 3 = L(h)
L(m)= ; F(m,h) = 6; L(m) + F(m,h) = + 6 = > 3 = L(h)
L(j)= 1; F(j,h) = 2; L(j) + F(j,h) = 1 + 2 = 3 = 3 = L(h)
Vậy u3 = j;
4) V-(j) = {k}
L(k)= 0; F(k,j) = 1; L(k) + F(k,j) = 0 + 1 = 1 = 1 = L(j)
Vậy u4 = k;
Suy ra đường đi từ k tới e là: <k, j, h, i, e>
11
Trang 153 Thuật toán duyệt các đỉnh của đồ thị theo theo chiều sâu
+ Input: - Đồ thị G liên thông, có n đỉnh, được cho bởi ma trận kề A=(aij)n
+ Output: - Các đỉnh của đồ thị
+ Giả mã:
1 For i:= 1 To n Do Đx[i]:= False;
2 Procedure DS(v: Đỉnh xuất phát);
Đx[v]:= True;
Output v;
For i:=1 To n Do
If (!Đx[i]) and (A[v,i]=1) Then DS(i);
4 Kết hợp thuật toán Dijsktra và tìm kiếm theo chiều sâu để giải quyết bài toán đặt ra
Ý tưởng: Đầu tiên, ta sử dụng tìm kiếm theo chiều sâu để tìm đường đi từ
đỉnh u đến đỉnh v Tiếp đến, ta đánh dấu các cạnh của đường đi này lại (hoặc coi
như đồ thị không tồn tại các cạnh thuộc đường đi này) Sau đó, ta sử dụng thuật
toán Dijsktra để tìm đường đi ngắn từ đỉnh u đến đỉnh v Tiếp đến, ta lưu lại kết quả
của hai đường đi này (tổng độ dài của hai đường đi, ) và tiếp tục làm lại từ đầu và
so sánh tổng độ dài của chúng với nhau để ta tìm được hai đường đi thỏa mãn yêu cầu bài toán là không có cạnh chung và tổng độ dài ngắn nhất
Để làm rõ ý tưởng trên, chúng tôi sử dụng một ví dụ để mô tả chi tiết ý tưởng của chúng tôi
Ví dụ: Cho đồ thị có hình dưới đây
Giả sử đỉnh u = 1 và đỉnh v = 4 Với ý tưởng trên, thực hiện như sau:
1
2
3
2
1
5
4
1
Trang 164 1
2
3
1
2
1
- Đầu tiên, sử dụng tìm kiếm theo chiều sâu để tìm đường đi từ đỉnh 1 đến đỉnh 4, ví dụ kết quả tìm kiếm đầu tiên là:
1->2->3->4, có tổng độ dài là: 4
- Tiếp đến, ta đánh dấu các cạnh của đường đi trên trong đồ thị (hoặc tạo ra
đồ thị mới không có các cạnh thuộc đường đi trên) Đồ thị sẽ có dạng như sau:
- Lúc này ta sử dụng thuật toán Dijsktra để tìm đường đi ngắn nhất từ đỉnh 1 đến đỉnh 4 trong đồ thị trên Kết quả tìm được sẽ là:
1->6->5->4, có tổng độ dài là: 4
- Như vậy, ta tìm được hai đường đi đầu tiên thỏa mãn điều kiện không có cạnh chung, đó là:
+ Đường 1: 1->2->3->4, có tổng độ dài là: 4 + Đường 2: 1->6->5->4, có tổng độ dài là: 4 Tổng độ dài của hai đường đi là: 8
13
Trang 17- Bây giờ ta quay lại bước đầu tiên sử dụng tìm kiếm theo chiêu sâu để tìm đường đi từ đỉnh 1 đến đỉnh 4 khác và cứ làm như vậy, ta lại được hai đường đi và
so sánh với kết quả của hai đường đi trước nếu kết quả nào có tổng độ dài hai đường đi nhỏ hơn thì chúng ta lưu lại
Độ phức tạp của thuật toán
Thuật toán Dijstra có độ phức tạp là O(n^2 + m)
Trong thuật toán DFS, một đường đi từ u đến v được tìm thấy với độ phức tạp O(n+m) và cần duyệt qua tất cả các đường đi từ u đến v nên độ phức tạp của hàm DFS là O((n + m)*p) với p là tổng số đường đi từ u đến v
Thực nghiệm chương trình
Sau khi hoàn thành thuật toán chúng tôi đã thử nghiệm với một số đồ thị và
có kết quả như sau:
Trên máy tính có cấu hình:
- CPU: Core 2 duo, 64bit Intel E6750 2.66GHz
- RAM: 2GB DDRII
Thời gian chạy 1s 3s 250s NA
14
Trang 18TÀI LIỆU THAM KHẢO
- Đào Thanh Tĩnh, Các bài giảng môn học Thiết kế và đánh giá thuật toán.
- Một số tài liệu về Lý thuyết đồ thị
- Một số trang web trên mạng Internet
15