1. Trang chủ
  2. » Luận Văn - Báo Cáo

Giải Thuật Và Lập Trình.pdf

316 2 0

Đang tải... (xem toàn văn)

Tài liệu hạn chế xem trước, để xem đầy đủ mời bạn chọn Tải xuống

THÔNG TIN TÀI LIỆU

Specialized School book in Computer Science (Bai giang chuyen de tin hoc) LÊ MINH HOÀNG Bài giảng chuyên đề Đại học Sư phạm Hà Nội, 1999 2002 Lời cảm ơn Tôi muốn bày tỏ lòng biết ơn đối với những ngườ[.]

LÊ MINH HOÀNG Bài giảng chuyên đề Đại học Sư phạm Hà Nội, 1999-2002 Lời cảm ơn Tôi muốn bày tỏ lòng biết ơn người thầy dạy tận tình năm tháng đầy khó khăn bước vào học tin học lập trình Sự hiểu biết lịng nhiệt tình thầy cung cấp cho kiến thức quý báu mà gương sáng cho noi theo đứng bục giảng với tư cách người thầy Cuốn tài liệu viết dựa tài liệu thu thập từ nhiều nguồn khác nhau, công sức nhiều hệ thầy trò giảng dạy học tập Khối Phổ thơng chun TốnTin, Đại học Sư phạm Hà Nội, cịn tơi người tổng hợp lại Qua đây, muốn gửi lời cảm ơn tới đồng nghiệp đọc đóng góp ý kiến quí báu, cảm ơn bạn học sinh - người trực tiếp làm nên sách Do thời gian hạn hẹp, số chuyên đề có chưa kịp chỉnh sửa đưa vào tài liệu Bạn đọc tham khảo thêm phần tra cứu Rất mong nhận lời nhận xét góp ý bạn để hoàn thiện sách Tokyo, 28 tháng năm 2003 Lê Minh Hoàng i MỤC LỤC PHẦN BÀI TOÁN LIỆT KÊ §1 NHẮC LẠI MỘT SỐ KIẾN THỨC ĐẠI SỐ TỔ HỢP 1.1 CHỈNH HỢP LẶP 1.2 CHỈNH HỢP KHÔNG LẶP .2 1.3 HOÁN VỊ 1.4 TỔ HỢP §2 PHƯƠNG PHÁP SINH (GENERATION) 2.1 SINH CÁC DÃY NHỊ PHÂN ĐỘ DÀI N 2.2 LIỆT KÊ CÁC TẬP CON K PHẦN TỬ 2.3 LIỆT KÊ CÁC HOÁN VỊ §3 THUẬT TỐN QUAY LUI 12 3.1 LIỆT KÊ CÁC DÃY NHỊ PHÂN ĐỘ DÀI N 12 3.2 LIỆT KÊ CÁC TẬP CON K PHẦN TỬ 13 3.3 LIỆT KÊ CÁC CHỈNH HỢP KHÔNG LẶP CHẬP K 15 3.4 BÀI TỐN PHÂN TÍCH SỐ 16 3.5 BÀI TOÁN XẾP HẬU .18 §4 KỸ THUẬT NHÁNH CẬN .24 4.1 BÀI TOÁN TỐI ƯU .24 4.2 SỰ BÙNG NỔ TỔ HỢP 24 4.3 MƠ HÌNH KỸ THUẬT NHÁNH CẬN 24 4.4 BÀI TOÁN NGƯỜI DU LỊCH 25 4.5 DÃY ABC 28 PHẦN CẤU TRÚC DỮ LIỆU VÀ GIẢI THUẬT 33 §1 CÁC BƯỚC CƠ BẢN KHI TIẾN HÀNH GIẢI CÁC BÀI TOÁN TIN HỌC .34 1.1 XÁC ĐỊNH BÀI TOÁN 34 1.2 TÌM CẤU TRÚC DỮ LIỆU BIỂU DIỄN BÀI TOÁN 34 1.3 TÌM THUẬT TỐN 35 1.4 LẬP TRÌNH .37 1.5 KIỂM THỬ 37 1.6 TỐI ƯU CHƯƠNG TRÌNH .38 §2 PHÂN TÍCH THỜI GIAN THỰC HIỆN GIẢI THUẬT 40 2.1 ĐỘ PHỨC TẠP TÍNH TỐN CỦA GIẢI THUẬT 40 2.2 XÁC ĐỊNH ĐỘ PHỨC TẠP TÍNH TỐN CỦA GIẢI THUẬT 40 2.3 ĐỘ PHỨC TẠP TÍNH TỐN VỚI TÌNH TRẠNG DỮ LIỆU VÀO 43 2.4 CHI PHÍ THỰC HIỆN THUẬT TOÁN 43 ii §3 ĐỆ QUY VÀ GIẢI THUẬT ĐỆ QUY 45 3.1 KHÁI NIỆM VỀ ĐỆ QUY 45 3.2 GIẢI THUẬT ĐỆ QUY 45 3.3 VÍ DỤ VỀ GIẢI THUẬT ĐỆ QUY 46 3.4 HIỆU LỰC CỦA ĐỆ QUY 50 §4 CẤU TRÚC DỮ LIỆU BIỂU DIỄN DANH SÁCH 52 4.1 KHÁI NIỆM DANH SÁCH 52 4.2 BIỂU DIỄN DANH SÁCH TRONG MÁY TÍNH 52 §5 NGĂN XẾP VÀ HÀNG ĐỢI 58 5.1 NGĂN XẾP (STACK) 58 5.2 HÀNG ĐỢI (QUEUE) 60 §6 CÂY (TREE) 64 6.1 ĐỊNH NGHĨA 64 6.2 CÂY NHỊ PHÂN (BINARY TREE) 65 6.3 BIỂU DIỄN CÂY NHỊ PHÂN 67 6.4 PHÉP DUYỆT CÂY NHỊ PHÂN 69 6.5 CÂY K_PHÂN 70 6.6 CÂY TỔNG QUÁT 71 §7 KÝ PHÁP TIỀN TỐ, TRUNG TỐ VÀ HẬU TỐ 74 7.1 BIỂU THỨC DƯỚI DẠNG CÂY NHỊ PHÂN 74 7.2 CÁC KÝ PHÁP CHO CÙNG MỘT BIỂU THỨC 74 7.3 CÁCH TÍNH GIÁ TRỊ BIỂU THỨC 75 7.4 CHUYỂN TỪ DẠNG TRUNG TỐ SANG DẠNG HẬU TỐ 78 7.5 XÂY DỰNG CÂY NHỊ PHÂN BIỂU DIỄN BIỂU THỨC 80 §8 SẮP XẾP (SORTING) 82 8.1 BÀI TOÁN SẮP XẾP 82 8.2 THUẬT TOÁN SẮP XẾP KIỂU CHỌN (SELECTIONSORT) 84 8.3 THUẬT TOÁN SẮP XẾP NỔI BỌT (BUBBLESORT) 85 8.4 THUẬT TOÁN SẮP XẾP KIỂU CHÈN 85 8.5 SHELLSORT 87 8.6 THUẬT TOÁN SẮP XẾP KIỂU PHÂN ĐOẠN (QUICKSORT) 88 8.7 THUẬT TOÁN SẮP XẾP KIỂU VUN ĐỐNG (HEAPSORT) 92 8.8 SẮP XẾP BẰNG PHÉP ĐẾM PHÂN PHỐI (DISTRIBUTION COUNTING) 95 8.9 TÍNH ỔN ĐỊNH CỦA THUẬT TOÁN SẮP XẾP (STABILITY) 96 8.10 THUẬT TOÁN SẮP XẾP BẰNG CƠ SỐ (RADIXSORT) 97 8.11 THUẬT TOÁN SẮP XẾP TRỘN (MERGESORT) 102 8.12 CÀI ĐẶT 105 8.13 ĐÁNH GIÁ, NHẬN XÉT 112 §9 TÌM KIẾM (SEARCHING) 116 iii 9.1 BÀI TOÁN TÌM KIẾM 116 9.2 TÌM KIẾM TUẦN TỰ (SEQUENTIAL SEARCH) 116 9.3 TÌM KIẾM NHỊ PHÂN (BINARY SEARCH) 116 9.4 CÂY NHỊ PHÂN TÌM KIẾM (BINARY SEARCH TREE - BST) .117 9.5 PHÉP BĂM (HASH) 122 9.6 KHOÁ SỐ VỚI BÀI TỐN TÌM KIẾM .122 9.7 CÂY TÌM KIẾM SỐ HỌC (DIGITAL SEARCH TREE - DST) 123 9.8 CÂY TÌM KIẾM CƠ SỐ (RADIX SEARCH TREE - RST) 126 9.9 NHỮNG NHẬN XÉT CUỐI CÙNG .131 PHẦN QUY HOẠCH ĐỘNG 133 §1 CƠNG THỨC TRUY HỒI 134 1.1 VÍ DỤ .134 1.2 CẢI TIẾN THỨ NHẤT 135 1.3 CẢI TIẾN THỨ HAI 137 1.4 CÀI ĐẶT ĐỆ QUY 137 §2 PHƯƠNG PHÁP QUY HOẠCH ĐỘNG 139 2.1 BÀI TOÁN QUY HOẠCH 139 2.2 PHƯƠNG PHÁP QUY HOẠCH ĐỘNG .139 §3 MỘT SỐ BÀI TOÁN QUY HOẠCH ĐỘNG 143 3.1 DÃY CON ĐƠN ĐIỆU TĂNG DÀI NHẤT 143 3.2 BÀI TOÁN CÁI TÚI 148 3.3 BIẾN ĐỔI XÂU .150 3.4 DÃY CON CÓ TỔNG CHIA HẾT CHO K 154 3.5 PHÉP NHÂN TỔ HỢP DÃY MA TRẬN 159 3.6 BÀI TẬP LUYỆN TẬP 163 PHẦN CÁC THUẬT TOÁN TRÊN ĐỒ THỊ 169 §1 CÁC KHÁI NIỆM CƠ BẢN .170 1.1 ĐỊNH NGHĨA ĐỒ THỊ (GRAPH) .170 1.2 CÁC KHÁI NIỆM 171 §2 BIỂU DIỄN ĐỒ THỊ TRÊN MÁY TÍNH 173 2.1 MA TRẬN LIỀN KỀ (MA TRẬN KỀ) 173 2.2 DANH SÁCH CẠNH 174 2.3 DANH SÁCH KỀ 175 2.4 NHẬN XÉT 176 §3 CÁC THUẬT TỐN TÌM KIẾM TRÊN ĐỒ THỊ .177 3.1 BÀI TOÁN .177 3.2 THUẬT TỐN TÌM KIẾM THEO CHIỀU SÂU (DEPTH FIRST SEARCH) 178 3.3 THUẬT TỐN TÌM KIẾM THEO CHIỀU RỘNG (BREADTH FIRST SEARCH) 184 iv 3.4 ĐỘ PHỨC TẠP TÍNH TỐN CỦA BFS VÀ DFS 189 §4 TÍNH LIÊN THÔNG CỦA ĐỒ THỊ 190 4.1 ĐỊNH NGHĨA 190 4.2 TÍNH LIÊN THƠNG TRONG ĐỒ THỊ VƠ HƯỚNG 191 4.3 ĐỒ THỊ ĐẦY ĐỦ VÀ THUẬT TOÁN WARSHALL 191 4.4 CÁC THÀNH PHẦN LIÊN THÔNG MẠNH 195 §5 VÀI ỨNG DỤNG CỦA CÁC THUẬT TỐN TÌM KIẾM TRÊN ĐỒ THỊ 205 5.1 XÂY DỰNG CÂY KHUNG CỦA ĐỒ THỊ 205 5.2 TẬP CÁC CHU TRÌNH CƠ BẢN CỦA ĐỒ THỊ 208 5.3 ĐỊNH CHIỀU ĐỒ THỊ VÀ BÀI TOÁN LIỆT KÊ CẦU 208 5.4 LIỆT KÊ KHỚP 214 §6 CHU TRÌNH EULER, ĐƯỜNG ĐI EULER, ĐỒ THỊ EULER 218 6.1 BÀI TOÁN CÁI CẦU 218 6.2 ĐỊNH NGHĨA 218 6.3 ĐỊNH LÝ 218 6.4 THUẬT TỐN FLEURY TÌM CHU TRÌNH EULER 219 6.5 CÀI ĐẶT 220 6.6 THUẬT TOÁN TỐT HƠN 222 §7 CHU TRÌNH HAMILTON, ĐƯỜNG ĐI HAMILTON, ĐỒ THỊ HAMILTON 225 7.1 ĐỊNH NGHĨA 225 7.2 ĐỊNH LÝ 225 7.3 CÀI ĐẶT 226 §8 BÀI TOÁN ĐƯỜNG ĐI NGẮN NHẤT 230 8.1 ĐỒ THỊ CÓ TRỌNG SỐ 230 8.2 BÀI TOÁN ĐƯỜNG ĐI NGẮN NHẤT 230 8.3 TRƯỜNG HỢP ĐỒ THỊ KHƠNG CĨ CHU TRÌNH ÂM - THUẬT TỐN FORD BELLMAN 232 8.4 TRƯỜNG HỢP TRỌNG SỐ TRÊN CÁC CUNG KHÔNG ÂM - THUẬT TOÁN DIJKSTRA 234 8.5 THUẬT TOÁN DIJKSTRA VÀ CẤU TRÚC HEAP 237 8.6 TRƯỜNG HỢP ĐỒ THỊ KHƠNG CĨ CHU TRÌNH - THỨ TỰ TƠ PÔ 240 8.7 ĐƯỜNG ĐI NGẮN NHẤT GIỮA MỌI CẶP ĐỈNH - THUẬT TOÁN FLOYD 242 8.8 NHẬN XÉT 245 §9 BÀI TOÁN CÂY KHUNG NHỎ NHẤT 247 9.1 BÀI TOÁN CÂY KHUNG NHỎ NHẤT 247 9.2 THUẬT TOÁN KRUSKAL (JOSEPH KRUSKAL - 1956) 247 9.3 THUẬT TOÁN PRIM (ROBERT PRIM - 1957) 252 §10 BÀI TOÁN LUỒNG CỰC ĐẠI TRÊN MẠNG 256 10.1 BÀI TOÁN 256 10.2 LÁT CẮT, ĐƯỜNG TĂNG LUỒNG, ĐỊNH LÝ FORD - FULKERSON 256 10.3 CÀI ĐẶT 258 v 10.4 THUẬT TOÁN FORD - FULKERSON (L.R.FORD & D.R.FULKERSON - 1962) 262 §11 BÀI TỐN TÌM BỘ GHÉP CỰC ĐẠI TRÊN ĐỒ THỊ HAI PHÍA 266 11.1 ĐỒ THỊ HAI PHÍA (BIPARTITE GRAPH) 266 11.2 BÀI TOÁN GHÉP ĐÔI KHÔNG TRỌNG VÀ CÁC KHÁI NIỆM 266 11.3 THUẬT TOÁN ĐƯỜNG MỞ 267 11.4 CÀI ĐẶT 268 §12 BÀI TỐN TÌM BỘ GHÉP CỰC ĐẠI VỚI TRỌNG SỐ CỰC TIỂU TRÊN ĐỒ THỊ HAI PHÍA - THUẬT TỐN HUNGARI .273 12.1 BÀI TỐN PHÂN CƠNG 273 12.2 PHÂN TÍCH .273 12.3 THUẬT TOÁN 274 12.4 CÀI ĐẶT 278 12.5 BÀI TOÁN TÌM BỘ GHÉP CỰC ĐẠI VỚI TRỌNG SỐ CỰC ĐẠI TRÊN ĐỒ THỊ HAI PHÍA .284 12.6 NÂNG CẤP 284 §13 BÀI TỐN TÌM BỘ GHÉP CỰC ĐẠI TRÊN ĐỒ THỊ 290 13.1 CÁC KHÁI NIỆM 290 13.2 THUẬT TOÁN EDMONDS (1965) 291 13.3 PHƯƠNG PHÁP LAWLER (1973) .293 13.4 CÀI ĐẶT 295 13.5 ĐỘ PHỨC TẠP TÍNH TỐN .299 TÀI LIỆU ĐỌC THÊM 301 vi HÌNH VẼ Hình 1: Cây tìm kiếm quay lui tốn liệt kê dãy nhị phân 13 Hình 2: Xếp quân hậu bàn cờ 8x8 19 Hình 3: Đường chéo ĐB-TN mang số 10 đường chéo ĐN-TB mang số 19 Hình 4: Lưu đồ thuật giải (Flowchart) 36 Hình 5: Tháp Hà Nội 49 Hình 6: Cấu trúc nút danh sách nối đơn 53 Hình 7: Danh sách nối đơn 53 Hình 8: Cấu trúc nút danh sách nối kép 55 Hình 9: Danh sách nối kép 55 Hình 10: Danh sách nối vòng hướng 55 Hình 11: Danh sách nối vịng hai hướng 56 Hình 12: Dùng danh sách vịng mô tả Queue 61 Hình 13: Di chuyển toa tàu 63 Hình 14: Di chuyển toa tàu (2) 63 Hình 15: Cây 64 Hình 16: Mức nút 65 Hình 17: Cây biểu diễn biểu thức 65 Hình 18: Các dạng nhị phân suy biến 66 Hình 19: Cây nhị phân hồn chỉnh nhị phân đầy đủ 66 Hình 20: Đánh số nút nhị phân đầy đủ để biểu diễn mảng 67 Hình 21: Nhược điểm phương pháp biểu diễn mảng 68 Hình 22: Cấu trúc nút nhị phân 68 Hình 23: Biểu diễn cấu trúc liên kết 69 Hình 24: Đánh số nút 3_phân để biểu diễn mảng 71 Hình 25: Biểu diễn tổng quát mảng 72 Hình 26: Cấu trúc nút tổng quát 73 Hình 27: Biểu thức dạng nhị phân 74 Hình 28: Vịng lặp QuickSort 89 Hình 29: Trạng thái trước gọi đệ quy 90 Hình 30: Heap 92 Hình 31: Vun đống 93 Hình 32: Đảo giá trị k1 cho kn xét phần lại 93 Hình 33: Vun phần cịn lại thành đống lại đảo trị k1 cho kn-1 94 Hình 34: Đánh số bit 97 Hình 35: Thuật tốn xếp trộn 102 Hình 36: Cài đặt thuật toán xếp với liệu lớn 114 Hình 37: Cây nhị phân tìm kiếm 118 Hình 38: Xóa nút BST 119 Hình 39 Xóa nút có nhánh BST 120 288 Chuyên đề repeat i := Pop; {Rút đỉnh X[i] khỏi hàng đợi} for j := to k {Quét Y_đỉnh chưa thăm} if Trace[j] = then begin w := GetC(i, j); {xét cạnh (X[i], Y[j])} if w = then {Nếu 0_cạnh} begin Trace[j] := i; {Lưu vết đường đi} if matchY[j] = then {Nếu j chưa ghép ghi nhận nơi kết thúc đường mở thoát} begin finish := j; Exit; end; Push(matchY[j]); {Nếu j ghép đẩy tiếp matchY[j] vào hàng đợi} end; if d[j] > w then {Cập nhật lại khoảng cách d[j] thấy cạnh (X[i], Y[j]) ngắn khoảng cách này} begin d[j] := w; arg[j] := i; end; end; until first > last; end; {Xoay trọng số cạnh} procedure SubX_AddY; var Delta: Integer; x, y: Integer; begin {Trước hết tính ∆ = giá trị nhỏ trọng số d[y], với y∈Y chưa thăm (y không thuộc pha)} Delta := maxC; for y := to k if (Trace[y] = 0) and (d[y] < Delta) then Delta := d[y]; {Trừ trọng số cạnh liên thuộc với start∈X ∆} Fx[start] := Fx[start] + Delta; for y := to k {Xét đỉnh y∈Y} if Trace[y] then {Nếu y thuộc pha} begin x := matchY[y]; {Thì x = matchY[y] phải thuộc pha} Fy[y] := Fy[y] - Delta; {Cộng trọng số cạnh liên thuộc với y lên ∆} Fx[x] := Fx[x] + Delta; {Trừ trọng số cạnh liên thuộc với x ∆} end else d[y] := d[y] - Delta; {Nếu y ∉ pha sau bước xoay, khoảng cách từ y đến pha giảm ∆} {Chuẩn bị tiếp tụcBFS} for y := to k if (Trace[y] = 0) and (d[y] = 0) then {Thăm đỉnh y∈Y tạo với pha 0_cạnh} begin Trace[y] := arg[y]; {Lưu vết đường đi} if matchY[y] = then {Nếu y chưa ghép ghi nhận đỉnh kết thúc đường mở thoát ngay} begin finish := y; Exit; end; Push(matchY[y]); {Nếu y ghép đẩy ln matchY[y] vào hàng đợi để chờ loang tiếp} end; end; procedure Enlarge; {Nới rộng ghép đường mở kết thúc finish} var x, next: Integer; Đại học Sư phạm Hà Nội, 1999-2002 Các thuật toán đồ thị begin repeat x := Trace[finish]; next := matchX[x]; matchX[x] := finish; matchY[finish] := x; finish := Next; until finish = 0; end; 289 x f next start procedure Solve; var x, y: Integer; begin for x := to k {Với X_đỉnh: } begin start := x; {Đặt nơi khởi đầu đường mở} InitBFS; {Khởi tạo pha} repeat FindAugmentingPath; {Tìm đường mở} if finish = then SubX_AddY; {Nếu khơng thấy xoay trọng số cạnh …} until finish 0; {Cho tới tìm đường mở} Enlarge; {Nới rộng ghép đường mở tìm được} end; end; procedure Result; var x, y, Count, W: Integer; f: Text; begin Assign(f, OutputFile); Rewrite(f); WriteLn(f, 'Optimal assignment:'); W := 0; Count := 0; for x := to m {Với X_đỉnh, xét cặp ghép tương ứng} begin y := matchX[x]; if c[x, y] < maxC then {Chỉ quan tâm đến cặp ghép có trọng số < maxC} begin Inc(Count); WriteLn(f, Count:5, ') X[', x, '] - Y[', y, '] ', c[x, y]); W := W + c[x, y]; end; end; WriteLn(f, 'Cost: ', W); Close(f); end; begin Enter; Init; Solve; Result; end Lê Minh Hồng x f next start 290 Chun đề §13 BÀI TỐN TÌM BỘ GHÉP CỰC ĐẠI TRÊN ĐỒ THỊ 13.1 CÁC KHÁI NIỆM Xét đồ thị G = (V, E), ghép đồ thị G tập cạnh đơi khơng có đỉnh chung Bài tốn tìm ghép cực đại đồ thị tổng quát phát biểu sau: Cho đồ thị G, phải tìm ghép cực đại G (bộ ghép có nhiều cạnh nhất) Với ghép M đồ thị G, ta gọi: Những cạnh thuộc M gọi cạnh ghép hay cạnh đậm Những cạnh không thuộc M gọi cạnh chưa ghép hay cạnh nhạt Những đỉnh đầu mút cạnh đậm gọi đỉnh ghép, đỉnh lại gọi đỉnh chưa ghép Một đường (đường khơng có đỉnh lặp lại) gọi đường pha bắt đầu cạnh nhạt cạnh đậm, nhạt nằm nối tiếp xen kẽ Một chu trình (chu trình khơng có đỉnh lặp lại) gọi Blossom qua đỉnh, bắt đầu kết thúc cạnh nhạt dọc chu trình, cạnh đậm, nhạt nằm nối tiếp xen kẽ Đỉnh xuất phát chu trình (cũng đỉnh kết thúc) gọi đỉnh sở (base) Blossom Đường mở đường pha bắt đầu đỉnh chưa ghép kết thúc đỉnh chưa ghép Ví dụ: Với đồ thị G ghép M Hình 87: Đường (8, 1, 2, 5, 6, 4) đường pha Chu trình (2, 3, 4, 6, 5, 2) Blossom Đường (8, 1, 2, 3, 4, 6, 5, 7) đường mở Đường (8, 1, 2, 3, 4, 6, 5, 2, 1, 9) có cạnh đậm/nhạt xen kẽ đường pha (và tất nhiên đường mở) khơng phải đường Đã ghép Chưa ghép Hình 87: Đồ thị G ghép M Ta dễ dàng suy tính chất sau Đường mở Blossom đường độ dài lẻ với số cạnh nhạt nhiều số cạnh đậm cạnh Đại học Sư phạm Hà Nội, 1999-2002 Các thuật toán đồ thị 291 Trong Blossom, đỉnh đỉnh sở đỉnh ghép đỉnh ghép với đỉnh phải thuộc Blossom Vì Blossom chu trình nên Blossom, đỉnh khơng phải đỉnh sở tồn hai đường pha từ đỉnh sở đến nó, đường kết thúc cạnh đậm đường kết thúc cạnh nhạt, hai đường pha hình thành cách dọc theo chu trình theo hai hướng ngược Như ví dụ Hình 87, đỉnh có hai đường pha đỉnh sở tới: (2, 3, 4) đường pha kết thúc cạnh đậm (2, 5, 6, 4) đường pha kết thúc cạnh nhạt 13.2 THUẬT TOÁN EDMONDS (1965) Cơ sở thuật toán định lý (C.Berge): Một ghép M đồ thị G cực đại không tồn đường mở M Thuật toán Edmonds: M := ∅; for (∀ đỉnh u chưa ghép) if then < Dọc đường mở: Loại bỏ cạnh đậm khỏi M; Thêm vào M cạnh nhạt; > Result: M ghép cực đại G Điều khó thuật tốn Edmonds phải xây dựng thuật tốn tìm đường mở xuất phát từ đỉnh chưa ghép Thuật tốn xây dựng cách kết hợp thuật tốn tìm kiếm đồ thị với phép chập Blossom Xét đường pha xuất phát từ đỉnh x chưa ghép Những đỉnh đến từ x đường pha kết thúc cạnh nhạt gán nhãn "nhạt", đỉnh đến từ x đường pha kết thúc cạnh đậm gán nhãn "đậm" Với Blossom, ta định nghĩa phép chập (shrink) phép thay đỉnh Blossom đỉnh Những cạnh nối đỉnh thuộc Blossom tới đỉnh v khơng thuộc Blossom thay cạnh nối đỉnh chập với v giữ nguyên tính đậm/nhạt Dễ thấy sau phép chập, cạnh đậm đảm bảo ghép đồ thị mới: Lê Minh Hoàng 292 Chuyên đề Shrink Shrink Blossom Blossom = đỉnh sở blossom = đỉnh chập từ blossom Hình 88: Phép chập Blossom Thuật tốn tìm đường mở phát biểu sau Trước hết đỉnh xuất phát x gán nhãn đậm Tiếp theo thuật tốn tìm kiếm đồ thị x, theo nguyên tắc: từ đỉnh đậm phép cạnh nhạt từ đỉnh nhạt cạnh đậm Mỗi thăm tới đỉnh, ta gán nhãn đậm/nhạt cho đỉnh tiếp tục thao tác tìm kiếm đồ thị bình thường Cũng trình tìm kiếm, phát thấy cạnh nhạt nối hai đỉnh đậm, ta dừng lại gán nhãn tiếp gặp tình trạng đỉnh có hai nhãn đậm/nhạt, trường hợp này, Blossom phát (xem tính chất Blossom) bị chập thành đỉnh, thuật toán bắt đầu lại với đồ thị trả lời câu hỏi: "có tồn đường mở xuất phát từ x hay khơng?" Nếu đường mở tìm khơng qua đỉnh chập ta việc tăng cặp dọc theo đường mở Nếu đường mở có qua đỉnh chập ta lại nở đỉnh chập thành Blossom để thay đỉnh chập đường mở đoạn đường xuyên qua Blossom: Expand Expand Hình 89: Nở Blossom để dị đường xun qua Blossom Đại học Sư phạm Hà Nội, 1999-2002 Các thuật tốn đồ thị 293 Lưu ý khơng phải Blossom bị chập, Blossom ảnh hưởng tới trình tìm đường mở phải chập để đảm bảo đường mở tìm đường Tuy nhiên việc cài đặt trực tiếp phép chập Blossom nở đỉnh rắc rối, địi hỏi chương trình với độ phức tạp O(n4) Dưới ta trình bày phương pháp cài đặt hiệu với độ phức tạp O(n3), phương pháp cài đặt không phức tạp, yêu cầu phải hiểu rõ chất thuật toán 13.3 PHƯƠNG PHÁP LAWLER (1973) Trong phương pháp Edmonds, sau chập Blossom thành đỉnh đỉnh hồn tồn lại nằm Blossom bị chập tiếp Phương pháp Lawler quan tâm đến đỉnh chập cuối cùng, đại diện cho Blossom (Outermost Blossom), đỉnh chập cuối định danh (đánh số) đỉnh sở Blossom Cũng thao tác chập/nở nói mà ta cần mở rộng khái niệm Blossom, coi Blossom tập đỉnh nở từ đỉnh chập khơng đơn chu trình pha Xét Blossom B có đỉnh sở đỉnh r Với ∀v∈B, v ≠ r, ta lưu lại hai đường pha từ r tới v, đường kết thúc cạnh đậm đường kết thúc cạnh nhạt, có hai loại vết gãn cho đỉnh v (hai vết cập nhật trình tìm đường): S[v] đỉnh liền trước v đường pha kết thúc cạnh đậm, khơng tồn đường pha loại S[v] = T[v] đỉnh liền trước v đường pha kết thúc cạnh nhạt, không tồn đường pha loại T[v] = Bên cạnh hai nhãn S T, đỉnh v cịn có thêm Nhãn b[v] đỉnh sở Blossom chứa v Hai đỉnh u v thuộc Blossom ⇔ b[u] = b[v] Nhãn match[v] đỉnh ghép với đỉnh v Nếu v chưa ghép match[v] = Khi thuật tốn tìm đường mở đỉnh x chưa ghép phát biểu sau: Bước 1: (Init) Hàng đợi Queue dùng để chứa đỉnh đậm chờ duyệt, ban đầu gồm đỉnh đậm x Với đỉnh u, khởi gán b[u] = u match[u] = với ∀u Gán S[x] ≠ 0; Với ∀u≠x, gán S[u] = 0;Với ∀v: gán T[v] = Bước 2: (BFS) Lặp lại bước sau hàng đợi rỗng: Với đỉnh đậm u lấy từ Queue, xét cạnh nhạt (u, v): Nếu v chưa thăm: Lê Minh Hoàng 294 Chuyên đề Nếu v đỉnh chưa ghép ⇒ Tìm thấy đường mở kết thúc v, dừng Nếu v đỉnh ghép ⇒ thăm v ⇒ thăm match[v] đẩy match[v] vào Queue Sau lần thăm, ý việc lưu vết (hai nhãn S T) Nếu v thăm Nếu v đỉnh nhạt b[v] = b[u] ⇒ bỏ qua Nếu v đỉnh đậm b[v] ≠ b[u] ta phát blossom chứa u v, đó: Phát đỉnh sở: Truy vết đường ngược từ hai đỉnh đậm u v theo hai đường pha nút gốc, chọn lấy đỉnh a đỉnh đậm chung gặp q trình truy vết ngược Khi Blossom phát có đỉnh sở a Gán lại vết: Gọi (a = i1, i2, …, ip = u) (a = j1, j2, …, jq = v) hai đường pha dẫn từ a tới u v Khi (a = i1, i2, …, ip = u, jq = v, jq-1, …, j1 = a) chu trình pha từ a tới u v quay trở a Bằng cách dọc theo chu trình theo hai hướng ngược nhau, ta gán lại tất nhãn S T đỉnh chu trình Lưu ý không gán lại nhãn S T cho đỉnh k mà b[k] = a, với đỉnh k có b[k] ≠ a bắt buộc phải gán lại nhãn S T theo chu trình S[k] T[k] trước có hay chưa Chập Blossom: Xét đỉnh v mà b[v]∈{b[i1], b[i2], …, b[ip], b[j1], b[j2], …, b[jq]}, gán lại b[v] = a Nếu v đỉnh đậm (có nhãn S[v] ≠ 0) mà chưa duyệt tới (chưa đẩy vào Queue) đẩy v vào Queue chờ duyệt tiếp bước sau Nếu trình hàng đợi rỗng tức không tồn đường mở x Sau số ví dụ trường hợp từ đỉnh đậm u xét cạnh nhạt (u, v): Trường hợp 1: v chưa thăm chưa ghép: S:2 T:3 v u x S:2 u x T:1 v T:1 ⇒ Tìm thấy đường mở Trường hợp 2: v chưa thăm ghép Đại học Sư phạm Hà Nội, 1999-2002 Các thuật toán đồ thị 295 S:2 S:2 T:3 S:4 v u x v u x T:1 T:1 ⇒ Thăm v lẫn match[v], gán nhãn T[v] S[match[v]] Trường hợp 3: v thăm, đỉnh đậm thuộc blossom với u T:3 S:5 T:7 S:4 u x T:1 S:2 T:3 S:7 v T:5 S:6 b[.] = ⇒ Không xét, bỏ qua Trường hợp 4: v thăm, đỉnh đậm b[u] ≠ b[v] T:3 S:4 T:3 S:5 T:7 S:4 a x T:1 S:2 x T:3 S:6 T:1 S:2 8 T:3 S:7 T:5 S:6 ⇒ Phát Blossom, tìm đỉnh sở a = 3, gán lại nhãn S T dọc chu trình pha Đẩy hai đỉnh đậm 4, vào hàng đợi, Tại bước sau, duyệt tới đỉnh 6, tìm thấy đường mở kết thúc 8, truy vết theo nhãn S T tìm đường (1, 2, 3, 4, 5, 7, 6, 8) Tư tưởng phương pháp Lawler dùng nhãn b[v] thay cho thao tác chập trực tiếp Blossom, dùng nhãn S T để truy vết tìm đường mở, tránh thao tác nở Blossom Phương pháp dựa nhận xét: Mỗi tìm đường mở, đường mở xun qua Blossom ngồi chắn phải vào Blossom từ nút sở thoát khỏi Blossom cạnh nhạt 13.4 CÀI ĐẶT Ta cài đặt phương pháp Lawler với khuôn dạng Input/Output sau: Lê Minh Hoàng 296 Chuyên đề Input: file văn GMATCH.INP • Dịng 1: Chứa hai số n, m số cạnh số đỉnh đồ thị cách dấu cách (n ≤ 100) • m dịng tiếp theo, dòng chứa hai số u, v tượng trưng cho cạnh (u, v) đồ thị Output: file văn GMATCH.OUT, ghi ghép cực đại tìm 10 GMATCH.INP 10 11 12 16 24 28 34 36 56 59 10 78 79 GMATCH.OUT 1) 2) 3) 4) 10 5) Chương trình sửa đổi chút mơ hình cài đặt dựa vào nhận xét: v đỉnh đậm ⇔ v = x match[v] đỉnh nhạt Nếu v đỉnh đậm S[v] = match[v] Vậy ta khơng cần phải sử dụng riêng mảng nhãn S[v], bước sửa vết, ta cần sửa nhãn vết T[v] mà Để kiểm tra đỉnh v ≠ x có phải đỉnh đậm hay khơng, ta kiểm tra điều kiện: match[v] có đỉnh nhạt hay khơng, hay T[match[v]] có khác hay khơng Chương trình sử dụng biến với vai trò sau: match[v] đỉnh ghép với đỉnh v b[v] đỉnh sở Blossom chứa v T[v] đỉnh liền trước v đường pha từ đỉnh xuất phát tới v kết thúc cạnh nhạt, T[v] = trình BFS chưa xét tới đỉnh nhạt v InQueue[v] biến Boolean, InQueue[v] = True ⇔ v đỉnh đậm đẩy vào Queue để chờ duyệt start finish: Nơi bắt đầu kết thúc đường mở P_4_13_1.PAS * Phương pháp Lawler áp dụng cho thuật toán Edmonds program MatchingInGeneralGraph; const InputFile = 'GMATCH.INP'; OutputFile = 'GMATCH.OUT'; max = 100; var a: array[1 max, max] of Boolean; match, Queue, b, T: array[1 max] of Integer; InQueue: array[1 max] of Boolean; n, first, last, start, finish: Integer; procedure Enter; var Đại học Sư phạm Hà Nội, 1999-2002 Các thuật toán đồ thị i, m, u, v: Integer; f: Text; begin Assign(f, InputFile); Reset(f); FillChar(a, SizeOf(a), False); ReadLn(f, n, m); for i := to m begin ReadLn(f, u, v); a[u, v] := True; a[v, u] := True; end; Close(f); end; procedure Init; {Khởi tạo ghép rỗng} begin FillChar(match, SizeOf(match), 0); end; procedure InitBFS; {Thủ tục gọi để khởi tạo trước tìm đường mở xuất phát từ start} var i: Integer; begin {Hàng đợi gồm đỉnh đậm start} first := 1; last := 1; Queue[1] := start; FillChar(InQueue, SizeOf(InQueue), False); InQueue[start] := True; {Các nhãn T khởi gán = 0} FillChar(T, SizeOF(T), 0); {Nút sở outermost blossom chứa i i} for i := to n b[i] := i; finish := 0; {finish = nghĩa chưa tìm thấy đường mở} end; procedure Push(v: Integer); {Đẩy đỉnh đậm v vào hàng đơi} begin Inc(last); Queue[last] := v; InQueue[v] := True; end; function Pop: Integer; {Lấy đỉnh đậm khỏi hàng đợi, trả kết hàm} begin Pop := Queue[first]; Inc(first); end; {Khó phương pháp Lawler thủ tục này: Thủ tục xử lý gặp cạnh nhạt nối hai đỉnh đậm p, q} procedure BlossomShrink(p, q: Integer); var i, NewBase: Integer; Mark: array[1 max] of Boolean; {Thủ tục tìm nút sở cách truy vết ngược theo đường pha từ p q} function FindCommonAncestor(p, q: Integer): Integer; var InPath: array[1 max] of Boolean; begin FillChar(InPath, SizeOf(Inpath), False); repeat {Truy vết từ p} p := b[p]; {Nhảy tới nút sở Blossom chứa p, phép nhảy để tăng tốc độ truy vết} Inpath[p] := True; {Đánh dấu nút đó} Lê Minh Hồng 297 298 Chuyên đề if p = start then Break; {Nếu truy đến nơi xuất phát dừng} p := T[match[p]]; {Nếu chưa đến start truy lùi tiếp hai bước, theo cạnh đậm theo cạnh nhạt} until False; repeat {Truy vết từ q, tương tự p} q := b[q]; if InPath[q] then Break; {Tuy nhiên chạm vào đường pha p dừng ngay} q := T[match[q]]; until False; FindCommonAncestor := q; {Ghi nhận đỉnh sở mới} end; procedure ResetTrace(x: Integer); {Gán lại nhãn vết dọc đường pha từ start tới x} var u, v: Integer; begin v := x; while b[v] NewBase {Truy vết đường pha từ start tới đỉnh đậm x} begin u := match[v]; Mark[b[v]] := True; {Đánh dấu nhãn blossom đỉnh đường đi} Mark[b[u]] := True; v := T[u]; if b[v] NewBase then T[v] := u; {Chỉ đặt lại vết T[v] b[v] nút sở mới} end; end; begin {BlossomShrink} FillChar(Mark, SizeOf(Mark), False); {Tất nhãn b[v] chưa bị đánh dấu} NewBase := FindCommonAncestor(p, q); {xác định nút sở} {Gán lại nhãn} ResetTrace(p); ResetTrace(q); if b[p] NewBase then T[p] := q; if b[q] NewBase then T[q] := p; {Chập blossom ⇔ gán lại nhãn b[i] blossom b[i] bị đánh dấu} for i := to n if Mark[b[i]] then b[i] := NewBase; {Xét đỉnh đậm i chưa đưa vào Queue nằm Blossom mới, đẩy i Queue để chờ duyệt tiếp bước sau} for i := to n if not InQueue[i] and (b[i] = NewBase) then Push(i); end; {Thủ tục tìm đường mở} procedure FindAugmentingPath; var u, v: Integer; begin InitBFS; {Khởi tạo} repeat {BFS} u := Pop; {Xét đỉnh v chưa duyệt, kề với u, không nằm Blossom với u, dĩ nhiên T[v] = (u, v) cạnh nhạt rồi} for v := to n if (T[v] = 0) and (a[u, v]) and (b[u] b[v]) then begin if match[v] = then {Nếu v chưa ghép ghi nhận đỉnh kết thúc đường mở thoát ngay} begin T[v] := u; finish := v; Exit; end; {Nếu v đỉnh đậm gán lại vết, chập Blossom …} if (v = start) or (T[match[v]] 0) then BlossomShrink(u, v) else {Nếu khơng ghi vết đường đi, thăm v, thăm match[v] đẩy tiếp match[v] vào Queue} Đại học Sư phạm Hà Nội, 1999-2002 Các thuật toán đồ thị 299 begin T[v] := u; Push(match[v]); end; end; until first > last; end; procedure Enlarge; {Nới rộng ghép đường mở start, kết thúc finish} var v, next: Integer; begin repeat v := T[finish]; next := match[v]; match[v] := finish; match[finish] := v; finish := next; until finish = 0; end; procedure Solve; {Thuật toán Edmonds} var u: Integer; begin for u := to n if match[u] = then begin start := u; {Với đỉnh chưa ghép start} FindAugmentingPath; {Tìm đường mở start} if finish then Enlarge; {Nếu thấy nới rộng ghép theo đường mở này} end; end; procedure Result; {In ghép tìm được} var u, count: Integer; f: Text; begin Assign(f, OutputFile); Rewrite(f); count := 0; for u := to n if match[u] > u then {Vừa tránh trùng lặp (u, v) (v, u), vừa loại đỉnh không ghép (match=0)} begin Inc(count); WriteLn(f, count, ') ', u, ' ', match[u]); end; Close(f); end; begin Enter; Init; Solve; Result; end 13.5 ĐỘ PHỨC TẠP TÍNH TỐN Thủ tục BlossomShrink có độ phức tạp O(n) Thủ tục FindAugmentingPath cần không n lần gọi thủ tục BlossomShrink, cộng thêm chi phí thuật tốn tìm kiếm theo chiều rộng, có độ phức tạp Lê Minh Hồng 300 Chun đề O(n2) Phương pháp Lawler cần không n lần gọi thủ tục FindAugmentingPath nên có độ phức tạp tính tốn O(n3) Cho đến nay, phương pháp tốt để giải tốn tìm ghép tổng qt đồ thị biết đến Micali Varizani (1980), có độ phức tạp tính tốn O( n m) Bạn tham khảo tài liệu khác Đại học Sư phạm Hà Nội, 1999-2002 TÀI LIỆU ĐỌC THÊM [1] Christian Charras, Thierry Lecroq Handbook of Exact String-Matching Algorithms Gần 20 thuật tốn tìm kiếm chuỗi, có diễn giải đầy đủ [2] Reinhard Diestel Graph Theory Một sách chuyên Lý thuyết đồ thị [3] Johan Håstad Advanced Algorithms [4] Andrew J Manson Speaker Matching Bài báo nói thuật tốn tìm ghép đồ thị tổng quát, trường hợp đồ thị có trọng số [5] Eva Milková Graph Theory and Information Technology Một số thuật toán toán bao trùm tối tiểu [6] Dave Mount Design and Analysis of Computer Algorithms [7] Nguyễn Xuân My, Trần Đỗ Hùng, Lê Sĩ Quang Một số vấn đề chọn lọc tin học Cuốn sách phù hợp cho học sinh phổ thơng trung học u thích việc giải tốn tin học [8] Nguyễn Đức Nghĩa, Nguyễn Tơ Thành Toán rời rạc Một sách dành cho sinh viên ngành tin học [9] Kenneth H Rosen Discrete Mathematics and its Applications (Bản dịch tiếng Việt: Toán học rời rạc ứng dụng tin học) Cuốn sách viết dạng giáo trình dễ hiểu, có hệ thống tập xếp khoa học [10] Robert Sedgewick Algorithms (Bản dịch tiếng Việt: Cẩm Nang Thuật Toán) Một sách tiện lợi cho tra cứu, đầy đủ thuật toán kinh điển In memory of committed teachers and excellent students Le Minh Hoang

Ngày đăng: 17/05/2023, 16:29

Xem thêm:

w