Giải thuật do tác giả Gallager và đồng sự đề xuất [19]. Có thể coi đây là phiên bản phân tán của giải thuật PRIM. Trong giải thuật PRIM, một nhánh của cây khung ban đầu là một nút tùy ý trong đồ thị, thuật toán sẽ kết nạp dần các nút vào nhánh, theo quy tắc cạnh nối nút này với nút ở trong nhánh là cạnh có trọng số nhỏ nhất, cuối cùng chúng ta sẽ nhận được cây khung MST của đồ thị. Giải thuật GHS83 duy trì một rừng cây khung (được xem như các mảnh), mỗi mảnh là một cây con của cây khung tối thiểu MST. Các mảnh được sát nhập qua các cạnh ngoài có trọng số tối thiểu của chúng cho đến khi chỉ còn một mảnh đơn bao trùm toàn bộ mạng.
Bài toán tìm cây khung MST được phát biểu hình thức như sau:
Bài toán: Cho một đồ thị G = (V, E), trong đó V, E tương ứng là tập các nút và các cạnh của đồ thị. Mỗi cạnh của đồ thị có gắn một trọng số phân biệt w(e). Hãy tìm một cây khung T = (V, E) sao cho tổng
E e ) e ( w nhỏ nhất.
Trọng số của một cây trong đồ thị là tổng trọng số của tất cả các cạnh trong cây,
mục tiêu của chúng ta là tìm một cây khung có trọng số tối thiểu, gọi là cây MST.
Mảnh MST: một mảnh của MST là một cây con của MST. Giải thuật bắt đầu với
các mảnh là mỗi nút riêng lẻ và kết thúc với một mảnh duy nhất chính là cây khung tối thiểu MST.
Liên kết ngoài: liên kết ngoài của một mảnh là liên kết nối một nút ở trong mảnh
e’ e e 5 4 8 3 1 7 2 6 4 5 8 3 1 7 2 6 e’
Hình 3.2-1. Minh họa chứng minh tính chất 1
Mỗi mảnh có một nút gốc, định danh của gốc là định danh của mảnh. Cạnh tốt nhất là cạnh có trọng số tối thiểu trong số các cạnh ngoài của mảnh.
Tính chất 1:
Cho một mảnh của MST, gọi e là một cạnh ngoài có trọng số tối thiểu của mảnh. Thì e MST.
Chứng minh. Gọi e là cạnh ngoài của mảnh F trong MST. Giả sử e không nằm
trong MST, MST e tạo thành một chu trình C, tồn tại ít nhất một cạnh ngoài của mảnh F là e e thuộc C, ta có w(e) > w(e). Kết nạp e vào MST và bỏ cạnh e, ta nhận được cây khung T’ có tổng trọng số của tất cả các cạch bé hơn cây khung MST ban đầu, điều này mâu thuẫn (hình 3.2-1).
Tính chất 2:
Nếu tất cả các cạnh của một đồ thị liên thông có các trọng số phân biệt, thì cây
khung MST là duy nhất.
Chứng minh. Chúng ta giả thiết phản chứng, rằng có hai cây khung tối thiểu phân biệt MST. Gọi e là cạnh có trọng số nhỏ nhất nằm ở một trong hai cây, nhưng không nằm trong cả hai, gọi T là tập các cạnh của MST chứa e và T’ là tập các cạnh của cây MST còn lại. Tập cạnh {e} T phải chứa một chu trình C, và tồn tại ít nhất một cạnh e trong C không nằm trong T (bởi vì T không chứa chu trình). Vì các trọng số là phân biệt và e nằm trong T nhưng không nằm trong T w(e) < w(e). Vì vậy
T e
Hình 3.2-2. Minh họa chứng minh tính chất 2
4 8 3 1 7 2 6 5 T’ 4 8 3 1 7 2 6 5 e’
{e} T - {e} là tập các cạnh của một cây khung có trọng số nhỏ hơn T, điều này mâu thuẫn (hình 3.2-2).
Ý tưởng
Ý tưởng của giải thuật dựa vào hai tính chất 1 và 2, giải thuật bắt đầu với các mảnh là một nút đơn nhất. Mỗi mảnh sẽ tìm cạnh ngoài có trọng số tối thiểu, và thực hiện trộn với mảnh khác qua cạnh này (tính chất 1). Tính chất thứ 2 đảm bảo rằng hợp của các mảnh này cũng là một mảnh trong cây MST.
Ở trạng thái ban đầu mỗi nút là một mảnh, mỗi mảnh tìm cạnh ngoài có trọng số tối thiểu (MOE: Minimum-weight Outgoing Edge) một cách không đồng bộ. Khi tìm thấy cạnh ngoài có trọng số tối thiểu, mảnh này sẽ cố gắng kết hợp với mảnh mà liên kết này dẫn đến. Ban đầu, mỗi mảnh chỉ có một nút nên có mức là 0. Giả sử rằng mảnh
F ở mức L 0 có cạnh liên kết ngoài dẫn tới và mảnh F có mức L. Mảnh F và F kết hợp với nhau chỉ khi thỏa mãn một trong hai điều kiện sau:
(1) Nếu L < L, thì mảnh F bị hấp thu bởi F, mảnh mở rộng có mức là L. (2) Nếu L = L và các mảnh F và F có cùng một cạnh ngoài trọng số tối thiểu,
thì hai mảnh F và F kết hợp thành một mảnh mới có mức là L + 1.
Trong tất cả các trường hợp khác, mảnh F đơn giản đợi mảnh F đạt đến mức đủ lớn để kết hợp với F theo các luật ở trên.
Trạng thái nút và cạnh:
- Mỗi nút có ba trạng thái
o sleeping: trạng thái khởi tạo của nút.
o find: khi nút tham gia vào việc tìm kiếm cạnh ngoài có trọng số tối thiểu trong mảnh chứa nó.
o found: khi đã tìm thấy cạnh tốt nhất của mảnh.
- Mỗi nút phân loại mỗi cạnh liền kề nó ở một trong ba trạng thái:
o branch: nếu cạnh là một nhánh trong mảnh hiện tại, nói cách khác đây
chính là một cạnh của cây MST.
o rejected: nếu cạnh nằm bên trong mảnh, nhưng không thuộc cây MST.
o basic: chưa được phân loại, có thể là cạnh trong hoặc ngoài mảnh.
Khởi tạo:
- Tất cả các nút có trạng thái khởi tạo là sleeping. - Tất cả các cạnh ở trạng thái basic.
- Ban đầu mỗi mảnh là một nút và ở mức 0, nút này cũng chính là gốc của mảnh, định danh của gốc là định danh của mảnh.
Bắt đầu lặp cho đến khi chỉ còn một mảnh duy nhất trong mạng: + Tìm cạnh ngoài có trọng số tối thiểu trong mảnh:
- Tìm cạnh ngoài có trọng số tối thiểu của nút:
o Gốc của một mảnh thay đổi trạng thái của nó thành find (ban đầu nút gốc thức dậy tự phát từ trạng thái ngủ sleeping hoặc được đánh thức bởi bất kỳ thông báo nào từ nút khác) và gửi một thông báo khởi tạo
initiate chứa định danh mảnh, số hiệu mức và trạng thái find tới tất cả các nút trong mảnh.
o Khi nút i nhận thông báo initiate, nó cập nhật định danh mảnh và số hiệu mức của nó. Nút i sau đó thay đổi trạng thái của nó thành find và tìm liên kết ngoài có trọng số tối thiểu cục bộ. Mỗi nút i sắp xếp cạnh liên thuộc nó có trạng thái basic theo trọng số của chúng với thứ tự tăng dần trong danh sách unusedi. Nút i tìm cạnh liên kết ngoài trọng số tối thiểu cục bộ như sau:
Nút i chọn cạnh tiếp theo (i,j) từ unusedi và gửi một thông báo
test với định danh mảnh và số hiệu mức qua cạnh này.
Nút j nhận được một thông báo test từ i, nó hoạt động như sau:
Nếu định danh mảnh của j giống với định danh mảnh của i, thì i và j thuộc cùng một mảnh, j xóa cạnh (i, j) từ
danh sách unusedj, thay đổi trạng thái cạnh này thành
rejected và j trả lời i bằng thông báo reject.
o Khi nút i nhận thông báo reject từ j, nó xóa cạnh (i, j) từ danh sách unusedi, thay đổi trạng thái cạnh này thành rejected và tiếp tục bằng cách gửi thông báo test qua cạnh tiếp theo trong danh sách của nó.
Nếu các định danh mảnh của i và j là khác nhau:
o Nếu Lj Li, nút j gửi một thông báo accept tới i. nút i nhận được thông báo accept sẽ lưu cạnh tốt nhất cục bộ của nó là (i,j), kết thúc quá trình tìm kiếm cạnh cục bộ tốt nhất tại nút i.
o Ngược lại, j làm trễ sự trả lời cho đến khi LjLi. /* Bởi khi hai mảnh sát nhập vào nhau, các nút trong các mảnh này không nhận được ngay tức thì thông báo mang định danh và mức của mảnh mới */
- Tìm cạnh ngoài có trọng số tối thiểu của mảnh:
/* Sau khi mỗi nút trong mảnh đã tìm thấy cạnh tốt nhất cục bộ của nó, chúng phối hợp với nhau để tìm cạnh tốt nhất toàn cục của mảnh*/
o Khi một nút i đã xác định cạnh tốt nhất cục bộ của nó là e:
Nếu i là nút lá, nó gửi một thông báo report chứa e đến cha của nó và chuyển sang trạng thái found.
Ngược lại, i là nút trong, i đợi cho đến khi nó tìm ra cạnh tốt nhất cục bộ và nhận các thông báo report từ tất cả các con của nó. Sau đó i gửi thông báo report với cạnh nhỏ nhất trong số các cạnh này tới cha của nóvà chuyển sang trạng thái found. o Nút gốc sau khi đã tìm ra cạnh tốt nhất cục bộ của nó và nhận các
thông báo từ tất cả các con của nó, nút gốc chọn cạnh có trọng số tối thiểu emin trong số các cạnh này.
Nếu chọn được emin, đây chính là cạnh tốt nhất của mảnh, nó gửi thông báo change-root, tới nút trong mảnh có emin là cạnh liên thuộc. Nút này trở thành gốc mới của mảnh, thay đổi trạng thái của emin là branch, và gửi một thông báo connect với số hiệu mức của nó qua emin.
Ngược lại, không có cạnh ngoài nào được tìm thấy, kết thúc giải thuật, mảnh hiện thời chính là cây MST cần tìm.
+ Kết hợp các mảnh với nhau:
Cho nút j trong mảnh G ở mức lj, nhận một thông báo connect từ nút i trong mảnh F ở mức li. Ta xét các trường hợp sau:
1. lj < li:
o Trước khi gửi một thông báo connect tới j, i sẽ phải gửi một thông báo
test tới j để xác định xem liệu rằng (i, j) có phải là một cạnh ngoài. Vì j
có số hiệu mức nhỏ hơn, nó sẽ làm trễ sự trả lời thông báo test cho đến khi số hiệu mức của nó trở thành ít nhất là li. Do đó, trưởng hợp này không xảy ra.
2. lj = li:
o Trong trường hợp này, nút j trì hoãn trả lời thông báo connect cho đến khi số hiệu mức của nó trở nên lớn hơn li (trong trường hợp này, nó hoạt động như trong trường hợp 3) hoặc nhận được thông báo change- root từ gốc của G, tức (i, j) là cạnh tốt nhất của G. Nếu (i,j) là cạnh tốt nhất của G thì F và G được trộn vào nhau. Nếu j > i thì j trở thành gốc của mảnh kết hợp. Nó tăng số hiệu mức của nó lên 1 và bắt đầu lần lặp mới bằng cách gửi một thông báo initiate tới các hàng xóm của nó. Ngược lại j gửi một thông báo connect tới i và i trở thành gốc mới của mảnh kết hợp, i tăng số hiệu mức của nó lên 1 và gửi thông báo
initiate cho các hàng xóm của nó để khởi tạo lần lặp mới cho mảnh kết
hợp. 3. lj > li:
(a). Nếu nút j đã nhận được một thông báo initiate và chưa gửi thông báo
report, thì nó gửi một thông báo initiate với định danh của mảnh G, số hiệu mức lj và trạng thái find tới i và đợi một thông báo report từ i
trước khi gửi thông báo report của nó, đồng thời j thay đổi trạng thái của cạnh (j,i) thành branch. Vì vậy, F được hấp thu vào G như là một phần của lần lặp hiện thời của G.
(b). Nếu j đã gửi thông báo report:
Trong trường hợp này, nút j gửi thông báo initiate với định danh của mảnh G, số hiệu mức lj và trạng thái found tới i, đồng thời j
thay đổi trạng thái của cạnh (j,i) thành branch. Một nút nhận được một thông báo initiate với trạng thái found thay đổi trạng thái của nó thành found, cập nhật số hiệu mức và định danh mảnh của nó và truyền thông báo tới các con của nó.
/*
Khi j đã gửi thông báo report, cạnh tốt nhất cục bộ của nó phải có trọng số nhỏ hơn trọng số của (i,j) (thật vậy, cạnh (i,j) không thể là cạnh tốt nhất cục bộ của j bởi vì i sẽ không trả lời một thông báo test
từ j vì i ở trong mảnh có mức thấp hơn, dẫn đến j không thể gửi thông báo report). Do đó cạnh tốt nhất cục bộ của j có trọng số nhỏ hơn cạnh ngoài có trọng số tối thiểu của F. Bởi vậy, sự tham gia của F trong việc tìm kiếm cạnh tốt nhất của G là không cần thiết.
*/
Chứng minh tính đúng đắn:
Ta thấy giải thuật chỉ tìm cạnh ngoài có trọng số tối thiểu từ các mảnh, thông báo
connect chỉ được gửi trên cạnh ngoài tối thiểu, giải thuật thỏa mãn các tính chất 1 và 2, do đó chúng ta nhận được cây MST.
Để chỉ ra rằng khóa chết không tồn tại, ta xét tập các mảnh tồn tại trong bất kỳ thời điểm nào. Ngoại trừ các mảnh có mức 0 bao gồm các nút trong trạng thái ngủ. Giả thiết rằng giải thuật đã được bắt đầu nhưng không kết thúc, tập các mảnh ở trên không rỗng và mỗi mảnh có một cạnh ngoài trọng số tối thiểu. Xét mảnh từ tập các mảnh có mức thấp nhất trong tập hợp với cạnh ngoài có trọng số nhỏ nhất trong tập đó. Mọi thông báo kiểm thử test từ mảnh đó hoặc sẽ đánh thức mảnh ở trạng thái ngủ sleeping
có mức không hoặc sẽ được phản hồi mà không cần đợi. Tương tự, một thông báo
connect từ mảnh đó sẽ đánh thức mảnh ở trạng thái ngủ có mức 0 hoặc sẽ chuyển đến
mảnh có mức cao hơn, hoặc sẽ chuyển đến mảnh đồng mức và có chung cạnh ngoài với trọng số tối thiểu, dẫn đến mảnh mới có mức cao hơn. Như vậy không có mảnh nào tồn tại vĩnh viễn không tồn tại khóa chết.
Ví dụ thực hiện:
Mạng ban đầu bao gồm 7 nút và 11 cạnh, mỗi cạnh được gắn trọng số như trong hình 3.2-1.a, tất cả các nút ở trạng thái sleeping và tất cả các cạnh ở trạng thái basic.
Ban đầu, mỗi nút ở trạng thái sleeping được coi là một mảnh, sẽ có một số nút thức dậy bắt đầu khởi động giải thuật. Khi một nút thức dậy từ trạng thái sleeping, nó thay đổi trạng thái của nó thành find và bắt đầu tìm kiếm cạnh liên kết ngoài có trọng số tối thiểu cục bộ của nút, việc tìm kiếm này sẽ đánh thức nút kề cận, khi một nút thức dậy và tìm thấy cạnh liên kết ngoài có trọng số tối thiểu, nó thay đổi trạng thái
thành found và gửi thông báo connect qua cạnh này. Hình 3.2-1.b, 3.2-1.c mô tả quá trình này.
Gọi mảnh ban đầu là Fi ứng với các nút i, ta có F1 và F3 đều có L1 = L3 = 0,
MOE1 = MOE3 = (1, 3) , vậy F1 và F3 sát nhập thành F3 có L3 = 1, gốc là nút 3. Tương tự F5 sát nhập F7 thành mảnh mới F7 với L7 = 1, gốc 7. Hình 3.2-1.d minh họa lần sát nhập đầu tiên.
Tiếp tục đợt lặp đầu tiên, mảnh F6 gửi thông báo connect tới F3, ta có L3 > L6 (1 > 0), vậy F3 hấp thu F6 tạo thành mảnh mới F3 có mức L3 = 1, và gốc là 3. Việc tìm kiếm MOE trên F3 làm thức nút 2, tương tự F3 hấp thu F2, F4 Hình 3.2-1.e minh họa sự hấp thu này.
4
Hình 3.2-1.a. Mạng ban đầu
5 7 2 12 8 3 6 9 10 15 3 6 2 4 1 5 7 4
Hình 3.2-1.b. Khởi động giải thuật
5 7 2 12 8 3 6 9 10 15 5 6 7 1 2 3 4 Hình 3.2-1.c. Đánh thức nút kề cận 5 7 2 12 8 3 6 9 10 15 4 2 4 6 5 7 3 1 Hình 3.2-1.d. Đợt sát nhập đầu tiên 5 7 2 12 8 3 6 9 10 15 4 F3 F7 1 4 7 5 2 6 3
Ở đợt thứ 2 (hình 3.2-1.e, hình 3.2-1.f), ta có L3 = L7 = 1 và MOE3 = MOE7 = (6,