4 Bài toán tối ưu
4.2.3 Bài toán tìm cây bao trùm có trọng số nhỏ nhất
Giả sử G = (V;E) là một đồ thị vô hướng liên thông. Khi đó đồ thị con T = (V0;E0) của G được gọi là cây bao trùm của G nếu T là cây và V0 = V.
Tương tự, giả sựG= (V;E)là một đồ thị vô hướng bất kì,G1;G2;· · · ;Gk
là các thành phần liên thông của G và T1;T2;· · · ;Tk tương ứng là các cây bao trùm củaG1;G2;· · · ;Gk. Khi đó rừng bao gồm các cây T1;T2;· · · ;Tk được gọi là rừng bao trùm của G.
Bây giờ giả sử G = (V;E;w) là một đồ thị vô hướng có trọng số liên thông, ở đây w : E −→ R là hàm trọng lượng cạnh với giá trị là các số thực. Với mỗi cây bao trùm T = (V;E0) của đồ thị có trọng số G, ta định nghĩa trọng số của cây T, kí hiệu là w(T) là giá trị:
w(T) = X l∈E0
w(l)
Bài toán tìm cây bao trùm có trọng số nhỏ nhất: Cho đồ thị có trọng số G= (V;E;w) như đã nói ở trên. Hãy tìm một cây bao trùm T = (V;E0)
của G sao cho trọng số w(T) của cây T là nhỏ nhất trong số các trọng số của các cây bao trùm của G.
a) Thuật toán Kruskal
Thuật toán: Giả sử G= (V;E;w) là đồ thị trọng số vô hướng liên thông với w : E −→ R
Bước 1: Xuất phát thuật toán từ đồ thị con T = (V0;E0) với V0 :=
V;E0 := E. Mỗi thành phần liên thông của đồ thị T xuất phát này chỉ bao gồm một đỉnh.
Bước 2: Sắp xếp các cạnh của trọng đồ G thành dãy S theo thứ tự không giảm của trọng lượng của các cạnh đó.
Bước 3: Lấy cạnh đầu tiên của dãy S chẳng hạn đó là cạnh e = xy, ta xét: Nếu hai đỉnh đầu mút x và y của e thuộc hai thành phần liên thông khác nhau C1 và C2 của T thì S = S\ {e};E0 = E0 ∪ {e} và ta nhập C1 với C2 thành một thành phần liên thông của đồ thị T mới nhận được. Ngược lại, S := S\ {e};E := E0 và các thành phần liên thông của T không thay đổi.
nếu T đã thành đồ thị liên thông thì ta dừng thuật toán. Khi đó đồ thị T = (V0;E0) nhận được chính là một cây bao trùm có trọng số nhỏ nhất của đồ thị G.
Định lý 4.5. Với mọi đồ thị vô hướng có trọng số G = (V;E;w), trong đó w : E −→ R. Thuật toán Kruskal luôn tìm được một cây bao trùm có trọng số nhỏ nhất của G.
Ví dụ 4.11. Bài toán: Sử dụng thuật toán Kruskal hãy tìm một cây bao trùm có trọng số nhỏ nhất của đồ thị có trọng số G = (V;E;w) được biểu diễn bởi hình:
Lời giải. Bước 1:
V0 := {s;a;b;c;d;e;f;t}
E0 := d
T := {V0;E0}
C := {{s};{a};{b};{c};{d};{e};{f};t}
C là tập các thành phần liên thông củaT
Bước 2: Sắp xếp các cạnh của G thành dãy S theo thứ tự không giảm của trọng lượng: S := {ed;ae;ad;be;ab;bc;ec;ef;cf;dt;sa;sb;sc;f t;et}
Bước 3: Lấy cạnh đầu tiên của dãy S là cạnh ed ra xét. Vì ed có các đỉnh đầu mút e và d thuộc các thành phần liên thông khác nhau của T nên:
S := S\ {ed} = {ae;ad;· · · }
E0 := E0 ∪ {ed}= {ed}
Bước 4:T không liên thông ta phải quay lại bước 3. Bước 3: Lấy cạnh đầu tiên của dãy S là cạnh ae ra xét. Ta thấy cạnh ae có các đỉnh đầu mút a và e thuộc các thành phần liên thông khác nhau của T. Vì vậy:
S := S\ {ae} = {ad;be;· · · }
E0 := E0 ∪ {ae}= {ed;ae}
C := {{s};{a;d;e};{b};{c};{f};{t}}
Bước 4: T không liên thông, ta quay lại bước 3.
Bước 3: Lấy cạnh đầu tiên của dãy S là cạnh ad ra xét. Ta thấy cạnh ad có hai đỉnh đầu mút là a và d cùng thuộc một thành phần liên thông là
{a;d;e} của T, vì vậy:
S := S\ {ad} = {be;ab;· · · }
E0 := E0 = {ed;ae}
C := {{s};{a;d;e};{b};{c};{f};{t}}
Bước 4: T không liên thông. Ta phải quay lại bước 3.
Bước 3: Lấy cạnh đầu tiên của dãy là cạnh be ra xét. Ta thấy cạnh be có hai đỉnh đầu mút làb và e thuộc hai thành phần liên thông khác nhau của T, vì vậy:
S := S\ {be}= {ad;bc;· · · }
E0 := E0 ∪ {be} = {ed;ae;be}
C := {{s};{a;b;d;e};{c};{f};{t}} · · ·
Tiếp tục thực hiện thuật toán ta sẽ tới lần lặp cuối cùng như sau:
Bước 3: Lấy cạnh đầu tiên của dãy S là cạnh sa ra xét. Ta thấy cạnh sa có các đỉnh đầu mút là s và a thuộc các thành phần liên thông khác nhau
của T. Vì vậy:
S := S\ {sa}= {sb;sc;f t;ct}
E0 := E0∪ {sa} = {ed;ae;be;bc;ef;dt;sa}
C := {{s;a;b;c;d;e;f;t}}
Bước 4: T liên thông . Ta dừng thuật toán và đồ thị T := (V0;E0) là cây bao trùm có trọng lượng nhỏ nhất của G, ở đây:
V0 = {s;a;b;c;d;e;f;t}
E0 := {ed;ea;be;bc;ef;dt;sa}
Nhận xét: Thuật toán Kruskal làm việc rất kém hiệu quả với các đồ thị trọng số có số cạnh lớn do phải chi phí nhiều thời gian để thực hiện việc sắp xếp các cạnh ở bước 2. Do vậy đối với các đồ thị có nhiều cạnh người ta thường sử dụng thuật toán Prim được mô tả dưới đây.
b) Thuật toán Prim
Thuật toán: Giả sử G = (V;E;w) là một đồ thị có trọng số liên thông với w : E −→ R. Ta định nghĩa nhãn của đỉnh v ∈ V và bộ [α(v);β(v)] với α(v) ∈ V và β(v) ∈ R. Nhãn của đỉnh v sẽ được lưu giữ như là giá trị của biến v và có thể thay đổi.
Bước 1: Khởi tạo và gán giá trị ban đầu cho các biến. V0 := V (biến V0 chứa tất cả các đỉnh của cây bao trùm) x := s (s là một đỉnh bất kì của V)
E0 := ∅ ( biến E0 chứa tất cả các cạnh của cây bao trùm cần tìm) U := V\ {s}
y := [s;∞] cho mọi y ∈ U
Bước 2: Đổi nhãn cho các đỉnh thuộc U. Với mọi đỉnh y ∈ U ta có: y = {
Bước 3: Tìm min
y∈U β(y) = β(vi) (*)
Bước 4: x := vi(nếu có một số đỉnh vi ∈ U thỏa mãn (*) thì ta chọn một đỉnh bất kì trong số các đỉnh đó)
Bước 5: Gán giá trị mới cho các biến E0 và U: E0 := E0∪ {xα(x)}
U := U\ {x}
Bước 6: Nếu U 6= ∅ thì ta quay lại bước 2.
Nếu U = ∅ thì ta dừng thuật toán và đồ thị T = (V0;E0) là một cây bao trùm có trọng lượng nhỏ nhất của đồ thị có trọng số G.
Định lý 4.6. Với mọi đồ thị có trọng số vô hướng liên thôngG= (V;E;w), trong đó w : E −→ R, thuật toán Prim luôn tìm được một cây bao trùm có trọng số nhỏ nhất của G.
Ví dụ 4.12. Bài toán: Tìm cây bao trùm có trọng số nhỏ nhất của đồ thị có trọng số G = (V;E;w) bằng thuật toán Prim.
Lời giải. Bước 1:
V0 := {s;a;b;c;d;e;f;t} x := s E0 := ∅ U := {a;b;c;d;e;f;t} y := [s;∞]cho mọi y ∈ U Lần lặp 1 Bước 2: a := [s; 5] ;b := [s; 5] ;c := [s; 6] ;d := [s;∅] ;e := [s;∅] ;f := [s;∅] ;t := [s;∅] Bước 3: min y∈U β(y) =β(a) =β(b) = 5 Bước 4: x := a Bước 5: E0 := E0 ∪ {as} = {as};U := U\ {a}= {b;c;d;e;f;t}
Bước 6: U 6= ∅. Ta phải quay lại bước 2. Lần lặp 2 Bước 2:b := [a; 2] ;c := [s; 6] ;d := [a; 1] ;e := [a; 1] ;f := [s;∅] ;t:= [s;∅] Bước 3: min y∈U β(y) = β(d) = β(e) = 1 Bước 4: x := d Bước 5: E0 := E0 ∪ {da}= {as;da};U := U\ {d} = {b;c;e;f;t}
Lần lặp 3 Bước 2:b := [a; 2] ;c := [s; 6] ;e := [d;−2] ;f := [s;∅] ;t := [d; 5] Bước 3: min y∈U β(y) =β(e) = −2 Bước 4: x := e Bước 5: E0 := E0 ∪ {ed} = {as;da;ed};U := U\ {e}= {b;c;f;t}
Bước 6: U 6= ∅. Ta phải quay lại bước 2. Lần lặp 4 Bước 2:b := [a; 2] ;c := [e; 3] ;f := [e; 3] ;t := [d; 5] Bước 3: min y∈U β(y) =β(b) = 2 Bước 4: x := b Bước 5: E0 := E0 ∪ {ba}= {as;da;ed;ba};U := U\ {b}= {c;f;t}
Bước 6: U 6= ∅. Ta phải quay lại bước 2. Lần lặp 5: Bước 2:c := [b; 2] ;f := [e; 3] ;t:= [d; 5] Bước 3: min y∈U β(y) =β(c) = 2 Bước 4: x := c Bước 5: E0 := E0 ∪ {cb}= {as;da;ed;ba;cb};U := U\ {c} = {f;t}
Bước 6: U 6= ∅. Ta phải quay lại bước 2. Lần lặp 6: Bước 2:f := [e; 3] ;t:= [d; 5] Bước 3: min y∈U β(y) =β(f) = 3 Bước 4: x := f Bước 5: E0 := E0 ∪ {f e} = {as;da;ed;ba;cb;f e};U := U\ {f} = {t}
Bước 6: U 6= ∅. Ta phải quay lại bước 2. Lần lặp 7: Bước 2:t := [d; 5] Bước 3: min y∈U β(y) =β(t) = 5 Bước 4: x := t Bước 5: E0 := E0 ∪ {td} = {as;da;ed;ba;cb;f e;td};U := U\ {t} = ∅
Bước 6: U = ∅. Ta dừng thuật toán và đồ thị T = (V0;E0) với V0 = {s;a;b;c;d;e;f;t} và E0 = {;da;ed;ba;cb;f e;td} là cây bao trùm có trọng số nhỏ nhất của G. Cùng một đồ thị nhưng hai cây bao trùm thực
hiện bằng thuật toán Kruskal và Prim là khác nhau. Nhưng hai cây bao trùm này đều có trọng lượng nhỏ nhất.