Tài liệu chuyên tin học quyển 2

240 30 0
Tài liệu chuyên tin học quyển 2

Đ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

Hồ sĩ đàm (Chủ biên) đỗ đức đông lê minh hoàng nguyễn hùng tài liệu giáo khoa chuyên tin Nhà xuất giáo dục việt nam CuuDuongThanCong.com https://fb.com/tailieudientucntt Công ty Cổ phần dịch vụ xuất Giáo dục Hà Nội - Nhà xuất Giáo dục Việt Nam giữ quyền công bố tác phẩm 349-2009/CXB/43-644/GD M sè : 8I746H9 CuuDuongThanCong.com https://fb.com/tailieudientucntt LỜI NÓI ðẦU Bộ Giáo dục ðào tạo ñã ban hành chương trình chuyên tin học cho lớp chuyên 10, 11, 12 Dựa theo chuyên ñề chuyên sâu chương trình nói trên, tác giả biên soạn sách chuyên tin học, bao gồm vấn ñề cấu trúc liệu, thuật toán cài ñặt chương trình Bộ sách gồm ba quyển, 1, Cấu trúc bao gồm: phần lí thuyết, giới thiệu khái niệm bản, cần thiết trực tiếp, thường dùng nhất; phần áp dụng, trình bày toán thường gặp, cách giải cài ñặt chương trình; cuối tập Các chun đề sách lựa chọn mang tính hệ thống từ ñến chuyên sâu Với trải nghiệm nhiều năm tham gia giảng dạy, bồi dưỡng học sinh chuyên tin học trường chuyên có truyền thống uy tín, tác giả lựa chọn, biên soạn nội dung bản, thiết yếu mà sử dụng để dạy học với mong muốn sách phục vụ không cho giáo viên học sinh chuyên PTTH mà cho giáo viên, học sinh chuyên tin học THCS làm tài liệu tham khảo cho việc dạy học Với kinh nghiệm nhiều năm tham gia bồi dưỡng học sinh, sinh viên tham gia kì thi học sinh giỏi Quốc gia, Quốc tế Hội thi Tin học trẻ Toàn quốc, Olympiad Sinh viên Tin học Tồn quốc, Kì thi lập trình viên Quốc tế khu vực ðơng Nam Á, tác giả ñã lựa chọn giới thiệu tập, lời giải có định hướng phục vụ cho khơng học sinh mà sinh viên làm tài liệu tham khảo tham gia kì thi Lần đầu tập sách biên soạn, thời gian trình độ có hạn chế nên chắn cịn nhiều thiếu sót, tác giả mong nhận ý kiến đóng góp bạn ñọc, ñồng nghiệp, sinh viên học sinh để sách ngày hồn thiện Các tác giả CuuDuongThanCong.com https://fb.com/tailieudientucntt CuuDuongThanCong.com https://fb.com/tailieudientucntt Chuyên ñề KIỂU DỮ LIỆU TRỪU TƯỢNG VÀ CẤU TRÚC DỮ LIỆU Kiểu liệu trừu tượng mơ hình tốn học với thao tác định nghĩa mơ hình Kiểu liệu trừu tượng khơng tồn ngơn ngữ lập trình mà dùng để tổng qt hóa tóm lược thao tác ñược thực liệu Kiểu liệu trừu tượng cài đặt máy tính cấu trúc liệu: Trong kỹ thuật lập trình cấu trúc (Structural Programming), cấu trúc liệu biến với thủ tục hàm thao tác biến Trong kỹ thuật lập trình hướng ñối tượng (ObjectOriented Programming), cấu trúc liệu kiến trúc thứ bậc lớp, thuộc tính phương thức tác động lên đối tượng hay vài thuộc tính đối tượng Trong chương này, khảo sát vài kiểu liệu trừu tượng cách cài ñặt chúng cấu trúc liệu Những kiểu liệu trừu tượng phức tạp mơ tả chi tiết thuật toán thấy cần thiết Danh sách 1.1 Khái niệm danh sách Danh sách tập thứ tự phần tử kiểu ðối với danh sách, người ta có số thao tác: Tìm phần tử danh sách, chèn phần tử vào danh sách, xóa phần tử khỏi danh sách, xếp lại phần tử danh sách theo trật tự v.v… Việc cài đặt danh sách máy tính tức tìm cấu trúc liệu cụ thể mà máy tính hiểu ñược ñể lưu phần tử danh sách đồng thời viết đoạn chương trình mơ tả thao tác cần thiết ñối với danh sách CuuDuongThanCong.com https://fb.com/tailieudientucntt Vì danh sách tập thứ tự phần tử kiểu, ta ký hiệu ˠ˗ˬ˥˭˥Jˮ kiểu liệu phần tử danh sách, cài đặt cụ thể, ˠ˗ˬ˥˭˥Jˮ kiểu liệu chương trình dịch chấp nhận (Số nguyên, số thực, ký tự, …) 1.2 Biểu diễn danh sách mảng Khi cài ñặt danh sách mảng chiều , ta cần có biến nguyên J lưu số phần tử có danh sách Nếu mảng ñược ñánh số bắt ñầu từ phần tử danh sách cất giữ mảng phần tử ñược ñánh số từ tới J: ˓ I{ŵ J{ a) Truy c p ph n t m ng Việc truy cập phần tử vị trí J mảng thực dễ dàng qua phần tử I Vì phần tử mảng có kích thước ñược lưu trữ liên tục nhớ, việc truy cập phần tử ñược thực phép tốn tính địa phần tử có thời gian tính tốn số Vì cài ñặt mảng, việc truy cập phần tử danh sách vị trí có độ phức tạp ß{ŵ{ b) Chèn ph n t vào m ng ðể chèn phần tử ˰ vào mảng vị trí J, trước hết ta dồn tất phần tử từ vị trí J tới tới vị trí J sau vị trí (tạo “chỗ trống” vị trí J), đặt giá trị ˰ vào vị trí J, tăng số phần tử mảng lên procedure Insert(p: Integer; const v: TElement); //Thủ tục chèn phần tử v vào vị trí p var i: Integer; begin for i := n downto p a[i + 1] := a[i]; a[p] := v; n := n + 1; end; Trường hợp tốt nhất, vị trí chèn nằm sau phần tử cuối danh sách (J J - ŵ), thời gian thực phép chèn ß{ŵ{ Trường hợp xấu nhất, ta cần chèn vị trí 1, thời gian thực phép chèn ß{J{ CuuDuongThanCong.com https://fb.com/tailieudientucntt Cũng dễ dàng chứng minh ñược thời gian thực trung bình phép chèn ß{J{ c) Xóa ph n t kh i m ng ðể xóa phần tử vị trí J mảng mà giữ nguyên thứ tự phần tử lại: Trước hết ta phải dồn tất phần tử từ vị trí J - ŵ tới J lên trước vị trí (thơng tin phần tử thứ J bị ghi ñè), sau ñó giảm số phần tử mảng (J) ñi procedure Delete(p: Integer); //Thủ tục xóa phần tử vị trí p var i: Integer; begin for i := p to n - a[i] := a[i + 1]; n := n - 1; end; Trường hợp tốt nhất, vị trí xóa nằm cuối danh sách (J J{, thời gian thực phép xóa ß{ŵ{ Trường hợp xấu nhất, ta cần xóa vị trí 1, thời gian thực phép xóa ß{J{ Cũng dễ dàng chứng minh thời gian thực trung bình phép xóa ß{J{ Trong trường hợp cần xóa phần tử mà khơng cần trì thứ tự phần tử khác, ta cần ñưa giá trị phần tử cuối vào vị trí cần xóa giảm số phần tử mảng (J) Khi thời gian thực phép xóa ß{ŵ{ 1.3 Biểu diễn danh sách danh sách nối ñơn Danh sách nối ñơn (Singly-linked list) gồm nút ñược nối với theo chiều Mỗi nút ghi (record) gồm hai trường: Trường ˩J˦J chứa giá trị lưu nút Trường ˬ˩J˫ chứa liên kết (con trỏ) tới nút kế tiếp, tức chứa thông tin đủ để biết nút nút danh sách nút nào, trường hợp nút cuối (khơng có nút kế tiếp), trường liên kết ˩J˦J ˬ˩J˫ ñược gán giá trị ñặc biệt, chẳng hạn trỏ J˩ˬ type PNode = ^TNode; //Kiểu trỏ tới nút TNode = record; //Kiểu biến ñộng chứa thông tin nút CuuDuongThanCong.com https://fb.com/tailieudientucntt info: TElement; link: PNode; end; Nút ñầu tiên danh sách (˨˥Iˤ) đóng vai trị quan trọng danh sách nối ñơn ðể duyệt danh sách nối ñơn, ta bắt ñầu từ nút ñầu tiên, dựa vào trường liên kết ñể ñi sang nút kế tiếp, ñến gặp giá trị đặc biệt (duyệt qua nút cuối) dừng lại a ˨˥Iˤ b c d e Hình 1.1 Danh sách nối ñơn a) Truy c p ph n t danh sách n i n Bản thân danh sách nối ñơn ñã kiểu liệu trừu tượng ðể cài ñặt kiểu liệu trừu tượng này, dùng mảng nút (trường ˬ˩J˫ chứa số nút kế tiếp) biến cấp phát ñộng (trường ˬ˩J˫ chứa trỏ tới nút kế tiếp) Tuy nhiên cấu trúc nối đơn, việc xác định phần tử ñứng thứ J danh sách bắt buộc phải duyệt từ ñầu danh sách qua J nút, việc thời gian trung bình ß{J{, tỏ khơng hiệu thao tác mảng Nói cách khác, danh sách nối ñơn tiện lợi cho việc truy cập không hiệu thực nhiều phép truy cập ngẫu nhiên b) Chèn ph n t vào danh sách n i n ðể chèn thêm nút chứa giá trị ˰ vào vị trí nút J danh sách nối ñơn, trước hết ta tạo nút ˚˥˱˚Jˤ˥ chứa giá trị ˰ cho nút liên kết tới J Nếu J ñang nút ñầu tiên danh sách (˨˥Iˤ) cập nhật lại ˨˥Iˤ ˚˥˱˚Jˤ˥, cịn J khơng phải nút danh sách, ta tìm nút J nút ñứng liền trước nút J chỉnh lại liên kết: J liên kết tới ˚˥˱˚Jˤ˥ thay liên kết tới thẳng J (h.1.2) CuuDuongThanCong.com https://fb.com/tailieudientucntt a b ˨˥Iˤ a ˨˥Iˤ b c d J J e c J d ˰ ˚˥˱˚Jˤ˥ e J Hình 1.2 Chèn phần tử vào danh sách nối ñơn procedure Insert(p: PNode; const v: TElement); //Thủ tục chèn phần tử v vào vị trí nút p var NewNode, q: PNode; begin New(NewNode); NewNode^.info := v; NewNode^.link := p; if head = p then head := NewNode else begin q := head; while q^.link ≠ p q := q^.link; q^.link := NewNode; end; end; Việc chỉnh lại liên kết phép chèn phần tử vào danh sách nối ñơn thời gian ß{ŵ{, nhiên việc tìm nút đứng liền trước nút J yêu cầu phải duyệt từ ñầu danh sách, việc thời gian trung bình ß{J{ Vậy phép chèn phần tử vào danh sách nối ñơn thời gian trung bình ß{J{ để thực c) Xóa ph n t kh i danh sách n i n: ðể xóa nút J khỏi danh sách nối đơn, gọi J˥˲ˮ nút ñứng liền sau J danh sách Xét hai trường hợp: Nếu J nút ñầu tiên danh sách ˨˥Iˤ J˥˲ˮ J ta đặt lại ˨˥Iˤ CuuDuongThanCong.com https://fb.com/tailieudientucntt Nếu J nút ñầu tiên danh sách, tìm nút J nút ñứng liền trước nút J chỉnh lại liên kết: J liên kết tới J˥˲ˮ thay liên kết tới J (h.1.3) Việc cuối huỷ nút J procedure Delete(p: PNode); //Thủ tục xóa nút p danh sách nối ñơn var next, q: PNode; begin next := p^.link; if p = head then head := next else begin q := head; while q^.link p q := q^.link; q^.link := next; end; Dispose(p); end; a b c d ˨˥Iˤ J J J˥˲ˮ a b d ˨˥Iˤ J J˥˲ˮ e e Hình 1.3 Xóa phần tử khỏi danh sách nối đơn Cũng giống phép chèn, phép xóa phần tử khỏi danh sách nối ñơn thời gian trung bình ß{J{ để thực Trên mô tả thao tác với danh sách biểu diễn dạng danh sách nối ñơn biến ñộng Chúng ta cài đặt danh sách nối đơn mảng, nút chứa phần tử mảng trường liên kết ˬ˩J˫ số nút Khi thao tác chèn/xóa phần tử ñược thực tương tự trên: const max = ; //Số phần tử cực ñại type TNode = record 10 CuuDuongThanCong.com https://fb.com/tailieudientucntt procedure MaxFlowByScaling; begin f := «Luồng 0»; k := C; //k sức chứa lớn cung E while k ≥ begin while «Tìm đường tăng luồng P có giá trị thặng dư ≥ k» «Tăng luồng dọc theo ñường P»; k := k div 2; end; end; d) Chứng minh bước vào lượt lặp vòng lặp: while k ≥ Lưu lượng lát cắt hẹp mạng thặng dư ˙ không vượt Ŷ˫É˗É e) Chứng minh lượt lặp vòng lặp: while k ≥ Vòng lặp while bên thực {˗{ lần với giá trị ˫ f) Chứng minh thuật tốn (maximum flow by scaling) cài đặt để tìm luồng cực đại ˙ thời gian {É˗É$ Ž‘‰ ˕{ Bộ ghép cực ñại ñồ thị hai phía 4.1 ðồ thị hai phía ðồ thị vơ hướng ˙ {ˢ ˗{ gọi đồ thị hai phía tập đỉnh ˢ chia làm hai tập rời nhau: I I cho cạnh ñồ thị ñều nối ñỉnh thuộc I với ñỉnh thuộc I Khi người ta cịn ký hiệu ˙ {I I ˗{ ðể thuận tiên trình bày, ta gọi ñỉnh thuộc I I_ñỉnh ñỉnh thuộc I I_ñỉnh 226 CuuDuongThanCong.com https://fb.com/tailieudientucntt I I Hình 2.12 ðồ thị hai phía Một đồ thị vơ hướng đồ thị hai phía thành phần liên thơng đồ thị hai phía ðể kiểm tra đồ thị vơ hướng liên thơng có phải đồ thị hai phía hay khơng, ta sử dụng thuật tốn tìm kiếm ñồ thị (BFS DFS) bắt ñầu từ ñỉnh J ðặt: I ɦ tập ñỉnh ñến ñược từ J qua số chẵn cạnh I ɦ tập ñỉnh ñến ñược từ J qua số lẻ cạnh Nếu tồn cạnh ñồ thị nối hai đỉnh I hai đỉnh I đồ thị cho khơng phải đồ thị hai phía, ngược lại ñồ thị ñã cho ñồ thị hai phía với cách phân hoạch tập đỉnh thành hai tập I I ðồ thị hai phía gặp nhiều mơ hình thực tế Chẳng hạn quan hệ nhân tập người đàn ơng tập người ñàn bà, việc sinh viên chọn trường, thầy giáo chọn tiết dạy thời khoá biểu v.v… 4.2 Bài tốn tìm ghép cực đại đồ thị hai phía Cho đồ thị hai phía ˙ {I I ˗{ Một ghép (matching) ˙ tập cạnh đơi khơng có đỉnh chung Có thể coi ghép tập H ʃ ˗ cho ñồ thị {I I H{, ñỉnh có bậc khơng q Vấn đề đặt tìm ghép lớn (maximum matching) (có nhiều cạnh nhất) đồ thị hai phía cho trước 4.3 Mơ hình luồng ðịnh hướng cạnh ˙ thành cung từ I sang I Thêm vào ñỉnh phát giả J cung nối từ J tới I_ñỉnh, thêm vào ñỉnh thu giả ˮ cung nối từ 227 CuuDuongThanCong.com https://fb.com/tailieudientucntt I_ñỉnh tới ˮ Sức chứa tất cung ñược ñặt 1, ta ñược mạng ˙ Xét luồng mạng ˙ có luồng cung số ngun, thấy cung có luồng từ I sang I tương ứng với ghép ˙ Bài tốn tìm ghép cực đại ˙ giải cách tìm luồng nguyên cực ñại ˙ J 1 2 3 I I ˮ Hình 2.13 Mơ hình luồng tốn tìm ghép cực đại ñồ thị hai phía Chúng ta phân tích số ñặc ñiểm ñường tăng luồng trường hợp để tìm cách cài đặt đơn giản Xét đồ thị hai phía ˙ {I I ˗{ ghép H ˙ Những ñỉnh thuộc H gọi ñỉnh ñã ghép (matched vertices), ñỉnh không thuộc H gọi ñỉnh chưa ghép (unmached vertices) Những cạnh thuộc H gọi cạnh ñã ghép, cạnh không thuộc H ñược gọi cạnh chưa ghép Nếu ñịnh hướng lại cạnh ñồ thị thành cung: Những cạnh chưa ghép ñịnh hướng từ I sang I, cạnh ñã ghép ñịnh hướng ngược lại từ I I Trên ñồ thị ñịnh hướng ñó, ñường ñi ñược gọi ñường pha (alternating path) ñường ñi từ I _ñỉnh chưa ghép tới I_ñỉnh chưa ghép gọi ñường mở (augmenting path) Dọc ñường pha, cạnh ñã ghép chưa ghép xen kẽ ðường mở ñường pha, ñi qua số lẻ cạnh, số cạnh chưa ghép nhiều số cạnh ghép cạnh Ví dụ với đồ thị hai phía hình 2.14 ghép {{˲# ˳# { {˲$ ˳$ {{ ðường ñi ˲% ˳$ ˲$ ˳# ñường pha, ñường ñi ˲% ˳$ ˲$ ˳# ˲# ˳% ñường mở 228 CuuDuongThanCong.com https://fb.com/tailieudientucntt 1 2 3 I I Hình 2.14 ðồ thị hai phía cạnh ñược ñịnh hướng theo ghép ðường mở thực chất ñường tăng luồng với giá trị thặng dư mơ hình luồng ðịnh lý 3-11 (mối quan hệ luồng cực ñại, ñường tăng luồng lát cắt hẹp nhất) ñã ñiều kiện cần ñủ ñể ghép H ghép cực đại khơng tồn đường mở ứng với H Nếu tồn ñường mở ˜ ứng với ghép H, ta mở rộng ghép cách: dọc ñường ˜ loại bỏ cạnh ñã ghép khỏi H thêm cạnh chưa ghép vào H Bộ ghép thu có lực lượng nhiều ghép cũ ñúng cạnh ðây thực chất phép tăng luồng dọc đường ˜ mơ hình luồng 4.4 Thuật tốn đường mở Từ mơ hình luồng tốn, xây dựng thuật tốn tìm ghép cực đại dựa chế tìm đường mở tăng cặp: Thuật tốn khởi tạo ghép trước bước vào vịng lặp Tại bước lặp, đường mở (thực chất ñường ñi từ I_ñỉnh chưa ghép tới I_đỉnh chưa ghép) tìm BFS DFS ghép ñược mở rộng dựa đường mở tìm M := «Một ghép bất kỳ, chẳng hạn: »; while «Tìm đường mở P» begin «Dọc đường P: - Loại bỏ cạnh ñã ghép khỏi M - Thêm cạnh chưa ghép vào M » end; 229 CuuDuongThanCong.com https://fb.com/tailieudientucntt Ví dụ với đồ thị hình 2.14 ghép H {{˲# ˳# { {˲$ ˳$ {{, thuật tốn tìm ñược ñường mở: ˲$ ˳# ˲# ˳% ˲% ˳$ Dọc ñường mở này, ta loại bỏ hai cạnh {˳$ ˲$ { {˳# ˲# { khỏi ghép thêm vào ghép ba cạnh {˲% ˳$ {, {˲$ ˳# {, {˲# ˳% {, ñược ghép cạnh ðồ thị với ghép không cịn đỉnh chưa ghép (khơng cịn đường mở) nên ghép cực đại (h.2.15) 1 1 2 2 3 3 I I I I Hình 2.15 Mở rộng ghép 4.5 Cài đặt Chúng ta cài đặt thuật tốn tìm ghép cực đại đồ thị hai phía ˙ {I I ˗{, ÉIÉ J, ÉIÉ J É˗É ˭ Các I_ñỉnh ñược ñánh số từ tới J I_ñỉnh ñược ñánh số từ tới J Khn dạng Input/Output sau: Input Dịng chứa ba số nguyên dương J J ˭ số I_ñỉnh, số I_ñỉnh số cạnh ñồ thị hai phía {J J ŵŴ& ˭ ŵŴ { ˭ dòng tiếp theo, dòng chứa hai số nguyên dương ˩ ˪ tương ứng với cạnh ˲ ˳ ñồ thị Output Bộ ghép cực ñại ñồ thị 230 CuuDuongThanCong.com https://fb.com/tailieudientucntt Sample Input Sample Output 3 1: x[2] - y[1] 2: x[3] - y[2] 2 3: x[1] - y[3] 1 2 3 I I 1 a) Bi u di n th hai phía b ghép ðồ thị hai phía ˙ {I I ˗{ ñược biểu diễn cách danh sách kề I_ñỉnh Cụ thể ta sử dụng mảng ˨˥Iˤ{ŵ J{ với phần tử ban ñầu ñược khởi tạo 0, mảng Iˤ˪{ŵ ˭{ mảng ˬ˩J˫{ŵ ˭{ Danh sách kề xây dựng q trình ñọc danh sách cạnh: ñọc cạnh {˲ ˳{ ta gán Iˤ˪{˩{ ɦ ˳ , ñặt ˬ˩J˫{˩{ ɦ ˨˥Iˤ{˲{ sau cập nhật lại ˥ ˨˥Iˤ{˲{ ɦ ˩ Khi đọc xong danh sách cạnh danh sách kề xây dựng xong, để duyệt I_đỉnh kề với đỉnh ˲ I, ta sử dụng thuật tốn sau: i := head[x]; //Từ đầu danh sách móc nối đỉnh kề x while i ≠ begin «Xử lý đỉnh adj[i]»; i := link[i]; //Nhảy sang phần tử danh sách móc nối end; Bộ ghép đồ thị hai phía ñược biểu diễn mảng ˭IˮI˨{ŵ J˳{, ñó ˭IˮI˨{˪{ số I_ñỉnh ghép với ñỉnh ˳ Nếu ˳ ñỉnh chưa ghép, ta gán ˭IˮI˨{˪{ ɦ Ŵ b) Tìm ng m ðường mở thực chất ñường ñi từ I_ñỉnh chưa ghép tới I_ñỉnh chưa ghép ñồ thị ñịnh hướng Ta tìm đường mở bước thuật tốn DFS: 231 CuuDuongThanCong.com https://fb.com/tailieudientucntt Bắt ñầu từ ñỉnh ˲ I chưa ghép, trước hết ta ñánh dấu I_ñỉnh mảng I˰I˩ˬ{ŵ J{ I˰I˩ˬ{˪{ ”—‡ đỉnh ˳ I chưa thăm I˰I˩ˬ{˪{ ƒŽ•‡ ñỉnh ˳ I ñã thăm (chỉ cần ñánh dấu I_ñỉnh) Thuật toán DFS để tìm đường mở xuất phát từ ˲ thực thủ tục ñệ quy ˢ˩J˩ˮ{˲{, thủ tục quét tất ñỉnh ˳ I chưa thăm nối từ I (dĩ nhiên qua cạnh chưa ghép), với xét ñến ñỉnh ˳ I, trước hết ta đánh dấu thăm ˳ Sau đó: Nếu ˳ ñã ghép, dựa vào kiện từ ˳ ñi ñến ñược ˭IˮI˨{˳{ qua cạnh ñã ghép hướng từ I I, lời gọi ñệ quy ˢ˩J˩ˮ{˭IˮI˨{˳{{ ñược thực ñể thăm ñỉnh ˭IˮI˨{˳{ I (thăm liền hai bước) Ngược lại ˳ chưa ghép, tức thuật tốn DFS tìm đường mở kết thúc ˳, ta khỏi dây chuyền đệ quy Q trình dây chuyền đệ quy thực chất lần ngược đường mở, ta lợi dụng q trình ñể mở rộng ghép dựa ñường mở ðể thuật tốn hoạt động hiệu hơn, ta sử dụng liên tiếp pha xử lý lô: Ký hiệu I tập I_ñỉnh chưa ghép, pha cố gắng mở rộng ghép dựa không mà nhiều đường mở khơng có đỉnh chung xuất phát từ ñỉnh khác thuộc I Cụ thể pha khởi tạo mảng ñánh dấu I˰I˩ˬ{ŵ J{ giá trị ”—‡, sau qt tất đỉnh ˲ I , thử tìm đường mở xuất phát từ ˲ mở rộng ghép tìm đường mở Trong pha có nhiều I_đỉnh ghép thêm procedure Visit(x X); //Thuật tốn DFS begin for y: (x, y) E //Quét Y_đỉnh kề x if avail[y] then //y chưa thăm, ý (x, y) chắn cạnh chưa ghép begin avail[y] := False; //Đánh dấu thăm y if match[y] = then Found := True //y chưa ghép, dựng cờ báo tìm thấy đường mở else Visit(match[y]); //y ghép, gọi đệ quy tiếp tục DFS if Found then // Ngay đường mở tìm thấy begin match[y] := x; //Chỉnh lại ghép theo đường mở 232 CuuDuongThanCong.com https://fb.com/tailieudientucntt Exit; //Thốt ln, lệnh Exit đặt dây chuyền đệ quy end; end; end; begin //Thuật tốn tìm ghép cực đại đồ thị hai phía «Khởi tạo ghép bất kỳ, chẳng hạn »; X* := «Tập đỉnh chưa ghép»; repeat //Lặp pha xử lý theo lô Old := |X*|; //Lưu số đỉnh chưa ghép bắt đầu pha for y Y avail[y] := True; //ðánh dấu Y_ñỉnh chưa thăm for x X* begin Found := False; //Cờ báo chưa tìm thấy đường mở Visit(x); //Tìm đường mở DFS if Found then X* := X* - {x}; //x ñã ñược ghép, loại bỏ x khỏi X* end; until |X*| = Old; //Lặp ghép thêm end; BMATCH.PAS Tìm ghép cực đại ñồ thị hai phía {$MODE OBJFPC} program MaximumBipartiteMatching; const maxN = 10000; maxM = 1000000; var p, q, m: Integer; adj: array[1 maxM] of Integer; link: array[1 maxM] of Integer; head: array[1 maxN + 1] of Integer; match: array[1 maxN] of Integer; avail: array[1 maxN] of Boolean; List: array[1 maxN] of Integer; nList: Integer; procedure Enter; //Nhập liệu var i, x, y: Integer; begin 233 CuuDuongThanCong.com https://fb.com/tailieudientucntt ReadLn(p, q, m); FillChar(head[1], p * SizeOf(head[1]), 0); for i := to m begin ReadLn(x, y); //Đọc cạnh (x, y), đưa y vào danh sách kề x adj[i] := y; link[i] := head[x]; head[x] := i; end; end; procedure Init; //Khởi tạo ghép rỗng var i: Integer; begin FillChar(match[1], q * SizeOf(match[1]), 0); for i := to p List[i] := i; //Mảng List chứa nList X_ñỉnh chưa ghép nList := p; end; procedure SuccessiveAugmentingPaths; var Found: Boolean; Old, i: Integer; procedure Visit(x: Integer); //Thuật toán DFS từ x∈X var i, y: Integer; begin i := head[x]; //Từ đầu danh sách kề x while i begin y := adj[i]; //Xét đỉnh y∈Y kề x if avail[y] then //y chưa thăm, hiển nhiên (x, y) cạnh chưa ghép begin avail[y] := False; //Đánh dấu thăm y if match[y] = then Found := True //y chưa ghép báo hiệu tìm thấy đường mở else Visit(match[y]); //Thăm match[y]∈X (thăm liền bước) if Found then //Tìm thấy đường mở begin match[y] := x; //Chỉnh lại ghép 234 CuuDuongThanCong.com https://fb.com/tailieudientucntt Exit; //Thoát dây chuyền đệ quy end; end; i := link[i]; //Chuyển sang ñỉnh danh sách ñỉnh kề x end; end; begin repeat Old := nList; //Lưu lại số X_đỉnh chưa ghép FillChar(avail[1], q * SizeOf(avail[1]), True); for i := nList downto begin Found := False; Visit(List[i]); //Cố ghép List[i] if Found then //Nếu ghép begin //Xóa List[i] khỏi danh sách X_đỉnh chưa ghép List[i] := List[nList]; Dec(nList); end; end; until Old = nList; //Không thể ghép thêm X_đỉnh end; procedure PrintResult; //In kết var j, k: Integer; begin k := 0; for j := to q if match[j] then begin Inc(k); WriteLn(k, ': x[', match[j], '] - y[', j, ']'); end; end; begin Enter; Init; SuccessiveAugmentingPath; PrintResult; 235 CuuDuongThanCong.com https://fb.com/tailieudientucntt end Nếu ñồ thị có J đỉnh (J J - J) ˭ cạnh, mảng ñánh dấu I˰I˩ˬ{ŵ J{ ñược khởi tạo lần pha, thời gian thực pha {J - ˭{ (suy từ thời gian thực giải thuật DFS) Các pha ñược thực lặp I pha thực xong mà khơng ghép thêm đỉnh Thuật tốn cần khơng q J lần thực pha xử lý lô, nên thời gian thực giải thuật tìm ghép cực đại đồ thị hai phía {J$ - J˭{ trường hợp xấu Cịn trường hợp tốt nhất, ta tìm ghép cực đại qua lượt thực pha xử lý lô, tức thời gian thực giải thuật DFS Cần lưu ý ñây ñánh giá  lớn cận thời gian thực Thuật toán chạy nhanh thực tế chưa có ñánh giá chặt Ý tưởng tìm lúc nhiều đường mở khơng có đỉnh chung nghiên cứu tốn luồng cực đại Dinic[10] Dựa ý tưởng này, Hopcroft Karp[21] tìm thuật tốn tìm ghép cực đại đồ thị hai phía thời gian  Ә ÉˢÉÉ˗Éә Thuật tốn Hopcroft-Karp trước hết sử dụng BFS ñể phân lớp ñỉnh theo ñộ dài ñường ñi ngắn sau ñó sử dụng DFS rừng BFS ñể xử lý lô tương tự cách làm Bài tập 2.35 Có J thợ J việc Mỗi thợ cho biết làm ñược việc nào, việc giao cho thợ thực hồn thành xong ñúng ñơn vị thời gian Tại thời ñiểm, thợ thực không việc Hãy phân công thợ làm công việc cho: Mỗi việc giao cho ñúng thợ thực Thời gian hồn thành tất cơng việc nhỏ Chú ý thợ thực song song cơng việc giao, việc người làm, không ảnh hưởng tới người khác 236 CuuDuongThanCong.com https://fb.com/tailieudientucntt 3.36 Một ghép H ñồ thị hai phía gọi tối đại việc bổ sung thêm cạnh vào H làm cho H khơng cịn ghép a) Chỉ ví dụ ghép tối đại khơng ghép cực đại đồ thị hai phía b) Tìm thuật tốn {É˗É{ để xác định ghép tối đại đồ thị hai phía c) Chứng minh ˓ ˔ hai ghép tối đại đồ thị hai phía É˓É ŶÉ˔É É˔É ŶÉ˓É Từ thuật tốn đường mở khởi tạo ghép tối đại số lượt tìm đường mở giảm nửa so với việc khởi tạo ghép rỗng 3.37 (Phủ ñỉnh – Vertex Cover) Cho ñồ thị hai phía ˙ {I I ˗{ Bài tốn đặt chọn tập ˕ gồm đỉnh cho cạnh ˗ liên thuộc với đỉnh thuộc ˕ Bài tốn tìm phủ đỉnh nhỏ ñồ thị tổng quát NP-ñầy ñủ, chưa có thuật tốn đa thức để giải Tuy đồ thị hai phía, phủ đỉnh nhỏ tìm dựa ghép cực đại Dựa vào mơ hình luồng tốn ghép cực đại, giả sử cung {I I{ có sức chứa - , cung {J I{ {I ˮ{ có sức chứa Gọi {˟ ˠ{ lát cắt hẹp mạng ðặt ˕ {˲ ˠ{ {˳ ˟{ a) Chứng minh ˕ phủ ñỉnh b) Chứng minh ˕ phủ ñỉnh nhỏ c) Giả sử ta tìm H ghép cực đại đồ thị hai phía, chắn khơng cịn tồn đường mở tương ứng với ghép H ðặt: I I ˳ {˲ I ˲ I chưa ghép ˲ ñến ñược ˳ qua ñường pha I ˲ ñã ghép ñỉnh ghép với ˲ không thuộc I { Chứng minh {I I { lát cắt hẹp d) Xây dựng thuật toán tìm phủ đỉnh nhỏ đồ thị hai phía dựa thuật tốn tìm ghép cực đại 3.38 Cho H ghép ñồ thị hai phía ˙ {I I ˗{ Gọi ˫ số I_đỉnh chưa ghép Chứng minh ba mệnh ñề sau ñây tương ñương: 237 CuuDuongThanCong.com https://fb.com/tailieudientucntt H ghép cực đại ˙ khơng có đường mở tương ứng với ghép H Tồn tập ˓ I cho É˚{˓{É É˓É ˫ Ở ñây ˚{˓{ tập I_đỉnh kề với đỉnh ˓ (Gợi ý: Chọn ˓ tập I_ñỉnh ñến ñược từ I_ñỉnh chưa ghép ñường pha) 2.39 (ðịnh lý Hall) Cho ˙ {I I ˗{ đồ thị hai phía có ÉIÉ ÉIÉ Chứng minh ˙ có ghép đầy đủ (bộ ghép mà ñỉnh ñều ñược ghép) É˓É É˚{˓{É với tập ˓ ʃ I 2.40 (Phủ ñường tối thiểu) Cho ˙ {ˢ ˗{ ñồ thị có hướng khơng có chu trình Một phủ đường (path cover) tập ˜ ñường ñi ˙ thỏa mãn: Với ñỉnh ˰ ˢ, tồn ñường ñi ˜ chứa ˰ ðường ñi bắt đầu kết thúc ñâu, tính ñường ñi ñộ dài (chỉ gồm đỉnh) Bài tốn đặt tìm phủ đường tối thiểu (minimum path cover): Phủ đường gồm đường ñi Gọi J số ñỉnh ñồ thị, ta ñánh số ñỉnh thuộc ˢ từ tới J Xây dựng đồ thị hai phía ˙ {I I ˗ { đó: I I {˲# ˲$ {˳# ˳$ ˲ { ˳ { Tập cạnh ˗ ñược xây dựng sau: Với cung {˩ ˪{ ˗ (h.2.16) cạnh ˲ ˳ ˗, ta thêm vào 238 CuuDuongThanCong.com https://fb.com/tailieudientucntt ˲# ŷ ŵ Ź Ÿ Ŷ ź ˲$ ˲% ˲& ˲' ˲ ˳# ˳$ ˳% ˳& ˳' ˜# ˜$ ŵŷŹ ŶŸź ˳ Hình 2.16 Bài tốn tìm phủ đường tối thiểu DAG quy tốn ghép cực đại đồ thị hai phía Gọi H ghép ˙ Khởi tạo ˜ tập J ñường ñi, ñường ñi gồm đỉnh ˙, ˜ phủ ñường Xét cạnh ghép, xét tới cạnh ˲ ˳ ta ñặt cạnh {˩ ˪{ nối hai ñường ñi ˜ thành ñường…Khi thuật tốn kết thúc, ˜ phủ đường a) Chứng minh tính bất biến vịng lặp: Tại bước xét tới cạnh ˲ ˳ H, cạnh {˩ ˪{ ˗ chắn nối hai ñường ñi ˜: ñường ñi kết thúc ˩ ñường ñi khác bắt ñầu ˪ Từ ñó tính đắn thuật tốn (Gợi ý: xét tới cạnh ˲ ˳ H ñặt cạnh {˩ ˪{ nối hai ñường ñi ˜ thành đường É˜É giảm Vậy thuật tốn kết thúc, É˜É J ÉHÉ , tức muốn É˜É ‹ ÉHÉ ƒš) b) Viết chương trình tìm phủ đường cực tiểu đồ thị có hướng khơng có chu trình c) Chỉ ví dụ để thấy thuật tốn khơng trường hợp ˙ có chu trình d) Chứng minh tìm thuật tốn giải tốn tìm phủ đường cực tiểu ñồ thị tổng quát thời gian đa thức tìm đường Hamilton đồ thị (nếu có) thời gian đa thức (Lý 239 CuuDuongThanCong.com https://fb.com/tailieudientucntt thuyết ñộ phức tạp tính tốn chứng minh đồ thị tổng qt, tốn tìm đường Hamilton NP-đầy đủ tốn tìm phủ đường cực tiểu NP-khó Có nghĩa thuật tốn với độ phức tạp đa thức để giải tốn phủ đường cực tiểu ñồ thị tổng quát phát minh lớn đáng ngạc nhiên) 2.41 Tự tìm hiểu thuật tốn Hopcroft-Karp Cài đặt so sánh tốc độ thực tế với thuật tốn 2.42 (Bộ ghép cực đại đồ thị quy hai phía) Một đồ thị vơ hướng ˙ {ˢ ˗{ gọi đồ thị quy bậc ˫ (˫-regular graph) bậc đỉnh ˫ ðồ thị quy bậc đồ thị khơng có cạnh nào, đồ thị quy bậc cạnh tạo thành ghép đầy đủ, đồ thị quy bậc có thành phần liên thơng chu trình đơn a) Chứng minh đồ thị hai phía ˙ ÉIÉ ÉIÉ {I I ˗{ đồ thị quy b) Chứng minh ln tồn ghép đầy đủ đồ thị hai phía quy bậc ˫ (˫ ŵ{ c) Tìm thuật tốn {É˗É Ž‘‰É˗É{ để tìm ghép đầy đủ đồ thị quy bậc ˫ ŵ 240 CuuDuongThanCong.com https://fb.com/tailieudientucntt ... mà sử dụng ñể dạy học với mong muốn sách phục vụ không cho giáo viên học sinh chuyên PTTH mà cho giáo viên, học sinh chuyên tin học THCS làm tài liệu tham khảo cho việc dạy học Với kinh nghiệm... chương trình; cuối tập Các chuyên ñề sách lựa chọn mang tính hệ thống từ ñến chuyên sâu Với trải nghiệm nhiều năm tham gia giảng dạy, bồi dưỡng học sinh chuyên tin học trường chuyên có truyền thống... nghiệm nhiều năm tham gia bồi dưỡng học sinh, sinh viên tham gia kì thi học sinh giỏi Quốc gia, Quốc tế Hội thi Tin học trẻ Toàn quốc, Olympiad Sinh viên Tin học Tồn quốc, Kì thi lập trình viên

Ngày đăng: 23/08/2020, 23:41

Tài liệu cùng người dùng

Tài liệu liên quan