Ví dụ, cấu trúc liên kết của một Website có thể được biểudiễn bằng một đồ thị có hướng như sau: các đỉnh là các trang web hiện có tại website, tồn tại một cạnh có hướng nối từ trang A tớ
Trang 1MỤC LỤC
MỤC LỤC 1
LỜI GIỚI THIỆU 2
YÊU CẦU CỦA ĐỀ TÀI 4
PHÂN CÔNG CÔNG VIỆC 6
CHƯƠNG I: MỘT SỐ KHÁI NIỆM 7
I.1 Cây 7
I.2 Cây phủ 8
I.3 Cây phủ nhỏ nhất 8
CHƯƠNG II:THUẬT TOÁN TÌM CÂY PHỦ NHỎ NHẤT 10
II.1 Thuật toán Prim (Robert Clay Prim – 1957) 10
II.2 Thuật toán Kruskal (Joseph Kruskal 1956) 12
II.3 Ví dụ 12
CHƯƠNG III: THIẾT KẾ CẤU TRÚC DỮ LIỆU CHO CÁC THUẬT TOÁN 16 III.1 Cấu trúc dữ liệu và giải thuật Prim 16
III.2 Cấu trúc dữ liệu và giải thuật Kruskal 20
CHƯƠNG IV: RỪNG PHỦ NHỎ NHẤT VÀ THUẬT TOÁN TÌM RỪNG PHỦ NHỎ NHẤT 23
IV.1 Khái niệm rừng 23
IV.2 Khái niệm rừng phủ nhỏ nhất 23
IV.3 Thuật toán tìm rừng phủ nhỏ nhất 24
IV.4 Cài đặt thuật toán tìm rừng phủ nhỏ nhất 25
CHƯƠNG V: CHƯƠNG TRÌNH TÌM RỪNG PHỦ NHỎ NHẤT 27
V.1 Dữ liệu đầu vào 27
V.2 Dữ liệu đầu ra 28
V.3 Mã nguồn chương trình 28
KẾT LUẬN 29
TÀI LIỆU THAM KHẢO 30
Trang 2LỜI GIỚI THIỆU
Lý thuyết đồ thị nghiên cứu các tính chất của đồ thị Một cách không chính
thức, đồ thị là một tập các đối tượng được gọi là các đỉnh (hoặc nút) nối với nhaubởi các cạnh (hoặc cung) Cạnh có thể có hướng hoặc vô hướng Đồ thị thườngđược vẽ dưới dạng một tập các điểm (các đỉnh nối với nhau bằng các đoạn thẳng(các cạnh)
Đồ thị biểu diễn được rất nhiều cấu trúc, nhiều bài toán thực tế có thể đượcbiểu diễn bằng đồ thị Ví dụ, cấu trúc liên kết của một Website có thể được biểudiễn bằng một đồ thị có hướng như sau: các đỉnh là các trang web hiện có tại
website, tồn tại một cạnh có hướng nối từ trang A tới trang B khi và chỉ khi A có chứa 1 liên kết tới B Do vậy, sự phát triển của các thuật toán xử lý đồ thị là một
trong các mối quan tâm chính của khoa học máy tính
Cấu trúc đồ thị có thể được mở rộng bằng cách gán trọng số cho mỗi cạnh
Có thể sử dụng đồ thị có trọng số để biểu diễn nhiều khái niệm khác nhau Ví dụ,nếu đồ thị biểu diễn một mạng đường giao thông, các trọng số có thể là độ dàicủa mỗi con đường Một cách khác để mở rộng đồ thị cơ bản là qui định hướng
cho các cạnh của đồ thị (như đối với các trang web, A liên kết tới B, nhưng B không nhất thiết cũng liên kết tới A) Loại đồ thị này được gọi là đồ thị có hướng.
Một đồ thị có hướng với các cạnh có trọng số được gọi là một lưới
Với một đồ thị liên thông, vô hướng cho trước, cây bao trùm của nó là một
đồ thị con có dạng cây và có tất cả các đỉnh liên thông với nhau Một đồ thị có
thể có nhiều cây bao phủ khác nhau Chúng ta cũng có thể gán một trọng số cho
mỗi cạnh và dùng nó để tính toán trọng số của một cây bao trùm bằng cách cộng
tất cả trọng số của cạnh trong cây bao trùm đó Khi đó, một cây bao trùm nhỏ
nhất là một cây bao trùm có trọng số bé hơn bằng trọng số của tất cả các cây bao
trùm khác Tổng quát hơn, bất kỳ một đồ thị vô hướng (không nhất thiết liên
thông) đều có một rừng bao phủ nhỏ nhất, là hội của các cây bao trùm nhỏ nhất
của các thành phần liên thông của nó
Trang 3Chúng tôi xin chân thành cảm ơn PGS TSKH Trần Quốc Chiến đã giảng dạy, hướng dẫn tận tình và cung cấp tài liệu tham khảo quý báu để chúng tôi hoàn thành đề tài này.
Nhóm học viên thực hiện
Lê Thị Anh Đào
Lê Văn Linh Nguyễn Thị Mai Phương Mai Văn Tùng
Huỳnh Anh Tuấn
Trang 4YÊU CẦU CỦA ĐỀ TÀI
CÂY PHỦ NHỎ NHẤT VÀ RỪNG PHỦ NHỎ NHẤT
1 Trình bày khái niệm cây, cây phủ, cây phủ nhỏ nhất, định lý về điều kiện cần và đủ để cây phủ nhỏ nhất
2 Trình bày thuật toán Prim và thuật toán Kruskal tìm cây phủ nhỏ nhất
3 Thiết kế cấu trúc dữ liệu và giải thuật Prim và giải thuật Kruskal tìm cây phủ nhỏ nhất
4 Sử dụng các thuật toán trên tìm rừng phủ nhỏ nhất cho đồ thị không liênthông
5 Viết chương trình cài đặt thuật toán tìm rừng phủ nhỏ nhất bằng ngôn ngữ C
File dữ liệu đầu vào: GRAPH.INP có cấu trúc
W1 {trọng số cây phủ nhỏ nhất của thành phần liên thông thứ 1}
x1, , xi {các đỉnh của thành phần liên thông thứ 1}
(u1, v1),(u2, v2) {các cạnh cây phủ nhỏ nhất của thành phần liên thông thứ 1}
W2 {trọng số cây phủ nhỏ nhất của thành phần liên thông thứ 2}
y1, , yj {các đỉnh của thành phần liên thông thứ 2}
(r1, t1), (r2, t2), {các cạnh cây phủ nhỏ nhất của thành phần liên thông thứ 2}
1) Ví dụ 1:
Trang 6PHÂN CÔNG CÔNG VIỆC
(theo mục lục) Chữ ký
Nhận xét của giáo viên
1 Lê Thị Mai Phương
Tìm hiểu các khái niệm về cây, cây phủ
và cây phủ nhỏ nhất
2 Huỳnh Anh Tuấn
Tìm hiểu thuật toán Prim và Kruskal để tìm cây phủ nhỏ nhất
3 Mai Văn Tùng
Thiết kế cấu trúc dữ liệu cho các thuật toán tìm cây phủ nhỏnhất
4 Lê Thị Anh Đào
Rừng phủ nhỏ nhất
và thuật toán tìm rừng phủ nhỏ nhất
5 Lê Văn Linh
Xây dựng chương trình tìm rừng phủ nhỏ nhất
Trang 7CHƯƠNG I: MỘT SỐ KHÁI NIỆM
I.1 Cây
Cây là đồ thị liên thông không có chu trình
Ví dụ: Đồ thị sau đây là cây.
Gốc của cây là một đỉnh đặc biệt, thông thường là đỉnh trên cùng
Mức của đỉnh là độ dài đường đi từ gốc đến đỉnh đó.
Độ cao của cây là mức lớn nhất của cây (tức mức của đỉnh cách xa gốc
Cây m-phân đầy đủ là cây mà mọi đỉnh trong có đúng m con.
Cây cân bằng là cây mà mọi đỉnh lá có mức là h hay h-1, trong đó h là
chiều cao của cây
Định lý (định lý tương đương): Cho đồ thị G = (V,E) có n đỉnh Các mệnh
Trang 81 G là một cây.
2 G liên thông và có n1 cạnh.
3 G không có chu trình và có n1 cạnh.
4 G không có chu trình và nếu bổ sung vào một cạnh nối hai đỉnh không
kề nhau thì xuất hiện một chu trình;
5 G liên thông và nếu bỏ đi một cạnh thì G mất tính liên thông;
6 Mỗi cặp đỉnh trong G được nối với nhau bằng đường đi duy nhất
I.2 Cây phủ
Cây phủ hay cây bao trùm của một đồ thị liên thông và có hướng G=(V,E)
là tập hợp các đỉnh và một số (có thể là tất cả) các cạnh của đồ thị sao cho khôngtồn tại các chu trình
Vậy:
- Cây phủ đồ thị N đỉnh sẽ có N-1 cạnh
- Giữa 2 đỉnh bất kỳ sẽ chỉ có một đường đi
Ví dụ: Cây T gọi là cây phủ hay cây bao trùm của G, nếu T là đồ thị con
phủ của G
Định lý: Đồ thị G = (V,E) có cây phủ khi và chỉ khi G liên thông
I.3 Cây phủ nhỏ nhất
Trang 9Cho G=(V,E, (cij)) là trọng đồ liên thông có trọng số (cij)
Cây phủ T nhỏ nhất của G là cây phủ T có tổng trọng số
T j i ij c T
d
, ) (
là nhỏ nhất
Vậy :
- Một đồ thị có thể có nhiều cây phủ
- Giá trị của một cây phủ là tổng trọng số của các cạnh của cây phủ đó
- Cây phủ nhỏ nhất là cây phủ có giá trị nhỏ nhất
Định lý: Cho đồ thị G = (V,E,(cij)) là đồ thị liên thông có trọng số (cij) Khi
đó T là cây phủ nhỏ nhất của G khi và chỉ khi mỗi cạnh e T có trọng số lớnnhất trên chu trình tạo bởi cạnh e và các cạnh của T
Chứng minh:
Điều kiện cần là hiển nhiên Ta chứng minh điều kiện đủ
Giả sử S là cây bất kỳ có k cạnh không thuộc T Ta chứng minh
d(S) d(T)quy nạp theo k
Gọi e1, e2, …, en-1 là các cạnh của T sắp theo thứ tự trọng số tăng dần:C(e1) c(e2) … c(en-1)
Bước cơ sở: k=0 Hiển nhiên là d(S) = d(T) vì S=T
Bước quy nạp: Giả sử mọi cây với số cạnh không thuộc T ít hơn k đều cótrọng số không nhỏ hơn d(T)
Gọi ei là cạnh đầu tiên trong dãy các cạnh của T không thuộc S Cạnh ei vàcác cạnh của S tạo thành chu trình duy nhất CS Chu trình CS bắt buộc phải chứacạnh e S \ T (vì T không chứa chu trình)
Cạnh e cùng với các cạnh của T tạo thành chu trình duy nhất CT Vì S chứacác cạnh e1,…, ei-1 và e, nên CT phải có cạnh ej với j i và ej S (nếu không, CT
Trang 10 S vô lý) Thay cạnh e bằng cạnh ei ta thu được cây phủ S’ có d(S’) d(S), vìc(e) c(ej) c(ei) Do S’ chỉ có k-1 cạnh không thuộc T nên theo giả thiết quynạp:
d(S) d(S’) d(T)Vậy, định lý đã được chứng minh
Phát biểu bài toán:
Cho G=(V,E) là đồ thị vô hướng liên thông có trọng số, mỗi cạnh eE cótrọng số m(e)0 Giả sử T=(VT,ET) là cây phủ của đồ thị G (VT=V) Ta gọi độdài m(T) của cây phủ T là tổng trọng số của các cạnh của nó:
(
e
e m T
Bài toán đặt ra là trong số tất cả các cây phủ của đồ thị G, hãy tìm cây phủ
có độ dài nhỏ nhất Cây phủ như vậy được gọi là cây phủ nhỏ nhất của đồ thị vàbài toán đặt ra được gọi là bài toán tìm cây phủ nhỏ nhất
II.1.Thuật toán Prim (Robert Clay Prim – 1957)
Đầu vào : Đồ thị G=(V,E) với trọng số
Các đỉnh ký hiệu là: 1, 2, , n
Trọng số của cạnh (i,j), (i,j)E, ký hiệu là cij
Đầu ra : Cây phủ nhỏ nhất T, hoặc kết luận đồ thị không liên thông.
Các bước :
(1) Khởi tạo: T là đồ thị gồm một đỉnh 1 và không có cạnh.
(2) Kiểm tra điều kiện kết thúc:
Nếu T có n-1 cạnh, Kết thúc Kết luận: T là cây phủ nhỏ nhất Ngược lại
sang bước (3)
(3) Thêm cạnh:
Trang 11Ký hiệu M là tập
M = { (i,j)E iT & j T }Tìm cạnh (k,h)M sao cho
ckh = min{cij (i,j)M}
Nếu ckh < , thêm cạnh (k,h) và đỉnh h vào T, sang bước (2)
Ngược lại, kết thúc Kết luận đồ thị G không liên thông
Chứng minh thuật toán
Cho cây phủ S bất kỳ của đồ thị G, ta phải chứng minh
d(S) d(T)
Ký hiệu các đỉnh và các cạnh lần lượt được thêm vào T là:
v1, v2, ,vn và e1, e2, ,en-1trong đó ek =(vk,vk+1), k=1,2, ,n-1
Nếu các cạnh của T cũng là cạnh của S thì hiển nhiên d(S) = d(T)
Ngược lại gọi em là cạnh đầu tiên trong dãy các cạnh của T xây dựng theothuật toán không thuộc S Cạnh em và các cạnh của S tạo thành chu trình duy nhấtC
Chu trình C chứa đỉnh vmTm, trong đó Tm = {v1, ,vm} là số đỉnh có được ởbước thêm cạnh em Chu trình C bắt buộc phải chứa cạnh e nối đỉnh của Tm vớiđỉnh không thuộc Tm (nếu không CT) Theo thuật toán thì cạnh e có trọng sốkhông nhỏ hơn trọng số của em Vì vậy thay cạnh e bằng cạnh em, ta thu được câyphủ S’ có d(S’) d(S) Lặp lại quá trình trên ta biến đổi cây S thành cây phủ T
và suy ra:
d(S) d(S’) d(T)
II.2.Thuật toán Kruskal (Joseph Kruskal 1956)
Đầu vào : Đồ thị G=(V,E) với trọng số
Các đỉnh ký hiệu là: 1, 2, , n
Trang 12Trọng số của cạnh (i,j), (i,j)E, ký hiệu là cij
Đầu ra : Cây phủ nhỏ nhất T, hoặc kết luận đồ thị không liên thông.
Chứng minh thuật toán
Cho e là cạnh bất kỳ không thuộc T Cạnh e cùng các cạnh của T tạo thànhchu trình duy nhất C
Với cạnh a bất kỳ trên C, ta phải có c(a) <=c(e) Thậtt vậy, ở bước (3) chọn
a, c(a)<=c(e), vì a là cạnh có trọng số nhỏ nhất mà khi thêm vào T khong tạothành chu trình (lúc đó e và các cạnh của T cũng không tạo thành chu trình).Theo định lý trên T là cây phủ nhỏ nhất
II.3.Ví dụ
Bằng thuật toán Prim và Kruskal hãy tìm cây phủ nhỏ nhất của đồ thị sau:
II.3.1 Thuật toán Prim
(1) Khởi tạo: T chỉ có đỉnh a, không có
cạnh:
T := ({a},), d(T) := 0
Trang 13(2) Kiểm tra: Số cạnh của T là 0, sang bước (3)
(3) Thêm cạnh: Tập M là
M = {(a,b), (a,c)}
Ta có: cab = 1 = min{cij (i,j)M}
Thêm đỉnh b và cạnh (a,b) vào T, ta có :
T :=({a,b}, {(a,b)}), d(T) := d(T) + cab = 1
(2) Kiểm tra: Số cạnh của T là 1, sang bước (3)
(3) Thêm cạnh: Tập M là
M = {(a,c), (b,d), (b,e)}
Ta có: cac = 1 = min{cij (i,j)M}
Thêm đỉnh c và cạnh (a,c) vào T, ta có :
T :=({a,b,c}, {(a,b), (a,c)}), d(T) := d(T) + cac = 2
(2) Kiểm tra: Số cạnh của T là 2, sang bước (3)
(3) Thêm cạnh: Tập M là
M = {(b,d), (b,e),(b,c),(c,e),(c,f)}
Ta có: cbd = 1 = min{cij (i,j)M}
Thêm đỉnh d và cạnh (b,d) vào T, ta có :
T :=({a,b,c,d}, {(a,b), (a,c), (b,d)}), d(T) := d(T) + cbd = 3
(2) Kiểm tra: Số cạnh của T là 3, sang bước (3)
(3) Thêm cạnh: Tập M là
M = {(b,e),(b,c),(c,e),(c,f), (d,e)}
Ta có: cbe = 1 = min{cij (i,j)M}
Thêm đỉnh e và cạnh (b,e) vào T, ta có :
T :=({a,b,c,d,e}, {(a,b), (a,c), (b,d), (b,e)}), d(T) := d(T) + cbe = 4
Trang 14(2) Kiểm tra: Số cạnh của T là 4, sang bước (3)
(3) Thêm cạnh: Tập M là
M = {(b,c),(c,e),(c,f), (d,e),(e,f)}
Ta có: ccf = 1 = min{cij (i,j)M}
Thêm đỉnh f và cạnh (c,f) vào T, ta có :
T :=({a,b,c,d,e,f}, {(a,b), (a,c), (b,d), (b,e),(c,f)}), d(T) := d(T) + ccf = 5
(2) Kiểm tra: Số cạnh của T là 5, Kết
thúc
Kết luận: Ta có cây phủ nhỏ nhất gồm
các cạnh
(a,b),(a,c),(b,d),(b,e),(c,f)với tổng trọng số là d(T) = 1+1+1+1+1 =
5
II.3.2 Thuật toán Kruskal
(1) Khởi tạo:
T:=({abcdef},), không có cạnh, số cạnh e:=0, trọng số d(T) := 0
(2) Kiểm tra: Số cạnh của T, e=0, sang bước (3)
(3) Thêm cạnh: Trong các cạnh không thuộc T cạnh (a,b) có độ dài nhỏ
nhất là 1 Thêm cạnh (a,b) vào T Ta có:
T=({abcdef},{(a,b)}),d(T):=d(T) + 1 = 1 và số cạnh e = 1
(2) Kiểm tra: Số cạnh của T là 1, sang bước (3)
(3) Thêm cạnh: Trong các cạnh không thuộc T thì cạnh (b,d) có độ dài nhỏ
nhất là 1 và không cùng các cạnh của T tạo thành chu trình Thêm cạnh (b,d) vào
T Ta có :
Trang 15T=({abcdef},{(a,b), (b,d)}),d(T):=d(T) + 1 = 2 và số cạnh e = 2
(2) Kiểm tra: Số cạnh của T là 2, sang bước (3)
(3) Thêm cạnh: Trong các cạnh không thuộc T thì cạnh (b,e) có độ dài nhỏ
nhất là 1 và không cùng các cạnh của T tạo thành chu trình Thêm cạnh (b,e) vào
T Ta có :
T=({abcdef},{(a,b), (b,d), (b,e)}),d(T):=d(T) + 1 = 3 và số cạnh e = 3
(2) Kiểm tra: Số cạnh của T là 3, sang bước (3)
(3) Thêm cạnh: Trong các cạnh không thuộc T thì cạnh (a,c) có độ dài nhỏ
nhất là 1 và không cùng các cạnh của T tạo thành chu trình Thêm cạnh (a,c) vào
T Ta có :
T=({abcdef},{(a,b), (b,d), (b,e), (a,c)}),d(T):=d(T) + 1 = 4 và số cạnh e = 4
(2) Kiểm tra: Số cạnh của T là 4, sang bước (3)
(3) Thêm cạnh: Trong các cạnh không thuộc T thì cạnh (c,f) có độ dài nhỏ
nhất là 1 và không cùng các cạnh của T tạo thành chu trình Thêm cạnh (c,f) vào
T Ta có :
T=({abcdef},{(a,b), (b,d), (b,e), (a,c), (c,f)}),d(T):=d(T) + 1 = 5 và số cạnh e = 5
(2) Kiểm tra: Số cạnh của T là 5 Kết thúc.
Kết luận: Ta có cây phủ nhỏ nhất gồm các cạnh (a,b), (b,d), (b,e), (a,c),
(c,f) với tổng trọng số là d(T) = 1+1+1+1+1 = 5
Trang 16Tóm lại: Ta có bảng đánh giá về 2 thuật toán như sau:
Áp dụng Thuật toán tốt nhất cho đồ
thị đầy đủ
Phù hợp với đồ thị thưa (đồ thị với số cạnh nhỏ hơn số đỉnh nhiều lần)
TOÁN
III.1 Cấu trúc dữ liệu và giải thuật Prim
III.1.1 Cấu trúc dữ liệu
Khai báo cấu trúc dữ liệu cho bài toán:
Đồ thị G = (V, E, w) được lưu trữ trong ma trận trọng số G[MAX][MAX], với MAX = 30;
G=aij với i=1 n, j=1 n (n số đỉnh của đồ thị G);
Trong đó:
aij = trọng số cạnh nối trực tiếp từ i đến j, aij là số nguyên (int);
aij = ∞ nếu giữa i và j không nối trực tiếp với nhau
Trang 17Trong thuật toán này, sử dụng:
Cây T được biểu diễn dưới dạng Ma trận trọng số;
Mảng một chiều VT[n] để lưu các đỉnh đã duyệt rồi (duyệt rồi = 1; chưaduyệt=0), nói cách khác T lưu giữ các đỉnh của cây phủ đang xây dựng.Kết thúc bài toán, T phải lưu n đỉnh của cây phủ nhỏ nhất;
File dữ liệu được soạn thảo bằng bất kỳ ngôn ngữ soạn thảo nào, có cấutrúc như sau:
Dòng đầu tiên gồm 2 số: n m
Trong đó n là số đỉnh, m là số cạnh của đồ thị.
m dòng tiếp theo (tương ứng với m cạnh) gồm 3 số: v 1 v 2 w
Trong đó, v1, v2 là đỉnh đầu và đỉnh cuối của cạnh (v1, v2); w là trọng số củacạnh;
Ví dụ: Nội dung file Test1.txt
Cụ thể, cấu trúc dữ liệu được khai báo (với ngôn ngữ C) như sau:
#define VC 99 //Đại lượng đặc trưng cho ∞
Trang 18#define MAX 30 //Số lượng đỉnh tối đa
typedef int GRAPH[MAX][MAX]; //Ma trận kề
typedef int ARRAY[MAX]; //Mảng một chiều
III.1.2 Thuật toán
Đầu vào: Đồ thị G = (V, E) với trọng số.
Các đỉnh ký hiệu là: 1, 2, … , n
Trọng số của cạnh (i, j) E, ký hiệu là cij
Đầu ra: Cây phủ nhỏ nhất T, hoặc kết luận đồ thị không liên thông.
Các bước thực hiện:
(1) Khởi tạo: T là đồ thị gồm một đỉnh 1 và không có cạnh
(2) Kiểm tra điều kiện kết thúc:
Nếu T có n - 1 cạnh, Kết thúc Kết luận: T là cây phủ nhỏ nhất Ngược lại
sang bước (3)
(3) Thêm cạnh: Ký hiệu M là tập
M = (i,j) E iT& jTTìm cạnh (k, h) M sao cho
ckh = min cij (i, j) M Nếu ckh <, thêm cạnh (k, h) và đỉnh h vào T, sang bước (2)
Ngược lại, tức M = Ø kết thúc Kết luận đồ thị G không liên thông
III.1.3 Cài đặt
int Prim(GRAPH G, int n, GRAPH T){
int e, u, v;
int i, j; hasEdge, min;
//Khởi tạo tất cả giá trị VT[i] = 0, i=0 to n-1
for(i=0; i<n; i++) VT[i] = 0;