BÀI GIẢNG GIẢI THUẬT VÀ LẬP TRÌNH - QUY HOẠCH ĐỘNG - LÊ MINH HOÀNG - 2 pot

36 738 2
BÀI GIẢNG GIẢI THUẬT VÀ LẬP TRÌNH - QUY HOẠCH ĐỘNG - LÊ MINH HOÀNG - 2 pot

Đ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

Bài toán liệt kê 23 Mã tuần: Cho bàn cờ tổng quát kích thước nxn quân Mã, hành trình quân Mã xuất phát từ ô đứng qua tất ô lại bàn cờ, ô lần Bài 10 Chuyển tất tập trước viết sinh sang quay lui Bài 11 Xét sơ đồ giao thông gồm n nút giao thông đánh số từ tới n m đoạn đường nối chúng, đoạn đường nối nút giao thông Hãy nhập liệu mạng lưới giao thơng đó, nhập số hiệu hai nút giao thơng s d Hãy in tất cách từ s tới d mà cách không qua nút giao thông lần Lê Minh Hồng 24 Chun đề §4 KỸ THUẬT NHÁNH CẬN 4.1 BÀI TỐN TỐI ƯU Một tốn đặt thực tế việc tìm nghiệm thoả mãn số điều kiện đó, nghiệm tốt theo tiêu cụ thể, nghiên cứu lời giải lớp toán tối ưu thuộc lĩnh vực quy hoạch toán học Tuy nhiên cần phải nói nhiều trường hợp chưa thể xây dựng thuật toán thực hữu hiệu để giải toán, mà việc tìm nghiệm chúng phải dựa mơ hình liệt kê tồn cấu hình đánh giá, tìm cấu hình tốt Việc liệt kê cấu hình cài đặt phương pháp liệt kê: Sinh tìm kiếm quay lui Dưới ta tìm hiểu phương pháp liệt kê thuật toán quay lui để tìm nghiệm tốn tối ưu 4.2 SỰ BÙNG NỔ TỔ HỢP Mơ hình thuật tốn quay lui tìm kiếm phân cấp Nếu giả thiết ứng với nút tương ứng với giá trị chọn cho xi ứng với nút tương ứng với giá trị mà xi+1 nhận n cấp có tới 2n nút lá, số lớn nhiều lần so với liệu đầu vào n Chính mà ta có thao tác thừa việc chọn xi phải trả giá lớn chi phí thực thi thuật tốn q trình tìm kiếm lịng vịng vơ nghĩa bước chọn xi+1, xi+2, … Khi đó, vấn đề đặt trình liệt kê lời giải ta cần tận dụng thơng tin tìm để loại bỏ sớm phương án chắn tối ưu Kỹ thuật gọi kỹ thuật đánh giá nhánh cận tiến trình quay lui 4.3 MƠ HÌNH KỸ THUẬT NHÁNH CẬN Dựa mơ hình thuật tốn quay lui, ta xây dựng mơ hình sau: procedure Init; begin ; end; {Thủ tục thử chọn cho xi tất giá trị nhận} procedure Try(i: Integer); begin for (Mọi giá trị V gán cho xi) begin ; if (Việc thử cịn hi vọng tìm cấu hình tốt BESTCONFIG) then if (xi phần tử cuối cấu hình) then else begin ; Try(i + 1); {Gọi đệ quy, chọn tiếp xi+1 } ; end; Đại học Sư phạm Hà Nội, 1999-2002 Bài toán liệt kê 25 end; end; begin Init; Try(1); end Kỹ thuật nhánh cận thêm vào cho thuật toán quay lui khả đánh giá theo bước, bước thứ i, giá trị thử gán cho xi khơng có hi vọng tìm thấy cấu hình tốt cấu hình BESTCONFIG thử giá trị khác mà không cần phải gọi đệ quy tìm tiếp hay ghi nhận kết làm Nghiệm toán làm tốt dần, tìm cấu hình (tốt BESTCONFIG - tất nhiên), ta không in kết mà cập nhật BESTCONFIG cấu hình vừa tìm 4.4 BÀI TỐN NGƯỜI DU LỊCH 4.4.1 Bài tốn Cho n thành phố đánh số từ đến n m tuyến đường giao thông hai chiều chúng, mạng lưới giao thông cho bảng C cấp nxn, Cij = Cji = Chi phí đoạn đường trực tiếp từ thành phố i đến thành phố j Giả thiết Cii = với ∀i, Cij = +∞ khơng có đường trực tiếp từ thành phố i đến thành phố j Một người du lịch xuất phát từ thành phố 1, muốn thăm tất thành phố lại thành phố lần cuối quay lại thành phố Hãy cho người hành trình với chi phí Bài tốn gọi tốn người du lịch hay tốn hành trình thương gia (Traveling Salesman) 4.4.2 Cách giải Hành trình cần tìm có dạng (x1 = 1, x2, …, xn, xn+1 = 1) xi xi+1: hai thành phố liên tiếp hành trình phải có đường trực tiếp (Cij ≠ +∞) ngoại trừ thành phố 1, không thành phố lặp lại hai lần Có nghĩa dãy (x1, x2, …, xn) lập thành hoán vị (1, 2, …, n) Duyệt quay lui: x2 chọn thành phố mà x1 có đường tới (trực tiếp), với cách thử chọn x2 x3 chọn thành phố mà x2 có đường tới (ngồi x1) Tổng qt: xi chọn thành phố chưa qua mà từ xi-1 có đường trực tiếp tới (1 ≤ i ≤ n) Nhánh cận: Khởi tạo cấu hình BestConfig có chi phí = +∞ Với bước thử chọn xi xem chi phí đường lúc có < Chi phí cấu hình BestConfig?, khơng nhỏ thử giá trị khác có tiếp tốn thêm Khi thử giá trị xn ta kiểm tra xem xn có đường trực tiếp khơng ? Nếu có đánh giá chi phí từ thành phố đến thành phố xn cộng với chi Lê Minh Hoàng 26 Chuyên đề phí từ xn trực tiếp 1, nhỏ chi phí đường BestConfig cập nhật lại BestConfig cách Sau thủ tục tìm kiếm quay lui mà chi phí BestConfig +∞ có nghĩa khơng tìm thấy hành trình thoả mãn điều kiện đề để cập nhật BestConfig, tốn khơng có lời giải, cịn chi phí BestConfig < +∞ in cấu hình BestConfig - hành trình tốn tìm Input: file văn TOURISM.INP • Dịng 1: Chứa số thành phố n (1 ≤ n ≤ 20) số tuyến đường m mạng lưới giao thơng • m dịng tiếp theo, dịng ghi số hiệu hai thành phố có đường trực tiếp chi phí qng đường (chi phí số nguyên dương ≤ 100) Output: file văn TOURISM.OUT, ghi hành trình tìm 1 2 TOURISM.INP 46 123 132 141 231 242 344 TOURISM.OUT 1->3->2->4->1 Cost: P_1_04_1.PAS * Kỹ thuật nhánh cận dùng cho toán người du lịch program TravellingSalesman; const InputFile = 'TOURISM.INP'; OutputFile = 'TOURISM.OUT'; max = 20; maxC = 20 * 100 + 1;{+∞} var C: array[1 max, max] of Integer; {Ma trận chi phí} X, BestWay: array[1 max + 1] of Integer; {X để thử khả năng, BestWay để ghi nhận nghiệm} T: array[1 max + 1] of Integer; {Ti để lưu chi phí từ X1 đến Xi} Free: array[1 max] of Boolean; {Free để đánh dấu, Freei= True chưa qua i} m, n: Integer; MinSpending: Integer; {Chi phí hành trình tối ưu} procedure Enter; var i, j, k: Integer; f: Text; begin Assign(f, InputFile); Reset(f); ReadLn(f, n, m); for i := to n {Khởi tạo bảng chi phí ban đầu} for j := to n if i = j then C[i, j] := else C[i, j] := maxC; for k := to m begin ReadLn(f, i, j, C[i, j]); C[j, i] := C[i, j]; {Chi phí chiều} end; Close(f); end; procedure Init; {Khởi tạo} Đại học Sư phạm Hà Nội, 1999-2002 Bài toán liệt kê 27 begin FillChar(Free, n, True); Free[1] := False; {Các thành phố chưa qua ngoại trừ thành phố 1} X[1] := 1; {Xuất phát từ thành phố 1} T[1] := 0; {Chi phí thành phố xuất phát 0} MinSpending := maxC; end; procedure Try(i: Integer); {Thử cách chọn xi} var j: Integer; begin for j := to n {Thử thành phố từ đến n} if Free[j] then {Nếu gặp thành phố chưa qua} begin X[i] := j; {Thử đi} T[i] := T[i - 1] + C[x[i - 1], j]; {Chi phí := Chi phí bước trước + chi phí đường trực tiếp} if T[i] < MinSpending then {Hiển nhiên có điều C[x[i - 1], j] < +∞ rồi} if i < n then {Nếu chưa đến xn} begin Free[j] := False; {Đánh dấu thành phố vừa thử} Try(i + 1); {Tìm khả chọn xi+1} Free[j] := True; {Bỏ đánh dấu} end else if T[n] + C[x[n], 1] < MinSpending then {Từ xn quay lại tốn chi phí trước} begin {Cập nhật BestConfig} BestWay := X; MinSpending := T[n] + C[x[n], 1]; end; end; end; procedure PrintResult; var i: Integer; f: Text; begin Assign(f, OutputFile); Rewrite(f); if MinSpending = maxC then WriteLn(f, 'NO SOLUTION') else for i := to n Write(f, BestWay[i], '->'); WriteLn(f, 1); WriteLn(f, 'Cost: ', MinSpending); Close(f); end; begin Enter; Init; Try(2); PrintResult; end Trên giải pháp nhánh cận thơ sơ giải tốn người du lịch, thực tế người ta cịn có nhiều cách đánh giá nhánh cận chặt Hãy tham khảo tài liệu khác để tìm hiểu phương pháp Lê Minh Hoàng 28 Chuyên đề 4.5 DÃY ABC Cho trước số nguyên dương N (N ≤ 100), tìm xâu gồm ký tự A, B, C thoả mãn điều kiện: Có độ dài N Hai đoạn liền khác (đoạn dãy ký tự liên tiếp xâu) Có ký tự C Cách giải: Khơng trình bày, đề nghị tự xem chương trình để hiểu, thích kỹ thuật nhánh cận sau: Nếu dãy X1X2…Xn thoả mãn đoạn liền khác nhau, ký tự liên tiếp phải có ký tự "C" Như với dãy gồm k ký tự liên tiếp dãy X số ký tự C dãy bắt buộc phải ≥ k div Tại bước thử chọn Xi, ta có Ti ký tự "C" đoạn chọn từ X1 đến Xi, cho dù bước đệ quy tiếp sau làm tốt nữa, số ký tự "C" phải chọn thêm ≥ (n - i) div Tức theo phương án chọn Xi số ký tự "C" dãy kết (khi chọn đến Xn) cho dù có làm tốt đến đâu ≥ Ti + (n - i) div Ta dùng số để đánh giá nhánh cận, nhiều số ký tự "C" BestConfig chắn có làm tiếp cấu hình tồi tệ hơn, ta bỏ qua cách chọn thử phương án khác Input: file văn ABC.INP chứa số nguyên dương n ≤ 100 Output: file văn ABC.OUT ghi xâu tìm ABC.INP 10 ABC.OUT ABACABCBAB "C" Letter Count : P_1_04_2.PAS * Dãy ABC program ABC_STRING; const InputFile = 'ABC.INP'; OutputFile = 'ABC.OUT'; max = 100; var N, MinC: Integer; X, Best: array[1 max] of 'A' 'C'; T: array[0 max] of Integer; {Ti cho biết số ký tự "C" đoạn từ X1 đến Xi} f: Text; {Hàm Same(i, l) cho biết xâu gồm l ký tự kết thúc Xi có trùng với xâu l ký tự liền trước khơng ?} function Same(i, l: Integer): Boolean; var j, k: Integer; begin j := i - l; {j vị trí cuối đoạn liền trước đoạn đó} for k := to l - if X[i - k] X[j - k] then begin Same := False; Exit; end; Same := True; Đại học Sư phạm Hà Nội, 1999-2002 Bài toán liệt kê 29 end; {Hàm Check(i) cho biết Xi có làm hỏng tính khơng lặp dãy X1X2 … Xi hay khơng} function Check(i: Integer): Boolean; var l: Integer; begin for l := to i div {Thử độ dài l} if Same(i, l) then {Nếu có xâu độ dài l kết thúc Xi bị trùng với xâu liền trước} begin Check := False; Exit; end; Check := True; end; {Giữ lại kết vừa tìm vào BestConfig (MinC mảng Best)} procedure KeepResult; begin MinC := T[N]; Best := X; end; {Thuật tốn quay lui có nhánh cận} procedure Try(i: Integer); {Thử giá trị Xi} var j: 'A' 'C'; begin for j := 'A' to 'C' {Xét tất giá trị} begin X[i] := j; if Check(i) then {Nếu thêm giá trị vào khơng làm hỏng tính khơng lặp } begin if j = 'C' then T[i] := T[i - 1] + {Tính Ti qua Ti - 1} else T[i] := T[i - 1]; if T[i] + (N - i) div < MinC then {Đánh giá nhánh cận} if i = N then KeepResult else Try(i + 1); end; end; end; procedure PrintResult; var i: Integer; begin for i := to N Write(f, Best[i]); WriteLn(f); WriteLn(f, '"C" Letter Count : ', MinC); end; begin Assign(f, InputFile); Reset(f); ReadLn(f, N); Close(f); Assign(f, OutputFile); Rewrite(f); T[0] := 0; MinC := N; {Khởi tạo cấu hình BestConfig ban đầu tồi} Try(1); PrintResult; Close(f); end Nếu ta thay tốn tìm xâu ký tự 'B' mà viết chương trình tương tự chương trình chạy chậm chút Lý do: thủ tục Try thử giá trị 'A', 'B', Lê Minh Hoàng 30 Chuyên đề đến 'C' Có nghĩa cách tìm, tiết kiệm sử dụng ký tự 'C' nên phần lớn liệu nhanh chóng tìm lời giải so với tốn tương ứng tìm xâu ký tự 'B' Chính mà đề u cầu ký tự 'B' ta lập chương trình làm u cầu ký tự 'C' nhất, có điều in kết quả, ta đổi vai trò 'B', 'C' cho Đây ví dụ cho thấy sức mạnh thuật toán quay lui kết hợp với kỹ thuật nhánh cận, viết quay lui tuý đánh giá nhánh cận khơng tốt với N = 100, không đủ kiên nhẫn để đợi chương trình cho kết (chỉ biết > giờ) Trong khi N = 100, với chương trình chạy hết giây cho kết xâu 27 ký tự 'C' Nói chung, ta gặp toán mà cần sử dụng thuật tốn, mơ hình kỹ thuật cài đặt giải Thơng thường tốn thực tế địi hỏi phải có tổng hợp, pha trộn nhiều thuật tốn, nhiều kỹ thuật có lời giải tốt Không lạm dụng kỹ thuật không xem thường phương pháp bắt tay vào giải toán tin học Thuật tốn quay lui khơng phải ngoại lệ, ta phải biết phối hợp cách uyển chuyển với thuật tốn khác thực công cụ mạnh Bài tập: Bài Một dãy dấu ngoặc hợp lệ dãy ký tự "(" ")" định nghĩa sau: i Dãy rỗng dãy dấu ngoặc hợp lệ độ sâu ii Nếu A dãy dấu ngoặc hợp lệ độ sâu k (A) dãy dấu ngoặc hợp lệ độ sâu k + iii Nếu A B hay dãy dấu ngoặc hợp lệ với độ sâu p q AB dãy dấu ngoặc hợp lệ độ sâu max(p, q) Độ dài dãy ngoặc tổng số ký tự "(" ")" Ví dụ: Có dãy dấu ngoặc hợp lệ độ dài độ sâu 3: ((()())) ((())()) ((()))() (()(())) ()((())) Bài toán đặt cho biết trước hai số nguyên dương n k Hãy liệt kê hết dãy ngoặc hợp lệ có độ dài n độ sâu k (làm với n lớn tốt) Bài Cho bãi mìn kích thước mxn vng, có chứa mìn khơng, để biểu diễn đồ mìn đó, người ta có hai cách: Cách 1: dùng đồ đánh dấu: sử dụng lưới vng kích thước mxn, ô (i, j) ghi số ô có mìn, ghi số khơng có mìn Đại học Sư phạm Hà Nội, 1999-2002 Bài toán liệt kê 31 Cách 2: dùng đồ mật độ: sử dụng lưới vng kích thước mxn, ô (i, j) ghi số khoảng từ đến cho biết tổng số mìn ô lân cận với ô (i, j) (ô lân cận với (i, j) có chung với (i, j) đỉnh) Giả thiết hai đồ ghi xác theo tình trạng mìn trường Về nguyên tắc, lúc cài bãi mìn phải vẽ đồ đánh dấu đồ mật độ, nhiên sau thời gian dài, người ta muốn gỡ mìn khỏi bãi vấn đề khó khăn đồ đánh dấu bị thất lạc !! Công việc lập trình viên là: Từ đồ mật độ, tái tạo lại đồ đánh dấu bãi mìn Dữ liệu: Vào từ file văn MINE.INP, số dịng cách dấu cách • Dòng 1: Ghi số nguyên dương m, n (2 ≤ m, n ≤ 30) • m dịng tiếp theo, dòng thứ i ghi n số hàng i đồ mật độ theo thứ tự từ trái qua phải Kết quả: Ghi file văn MINE.OUT, số dịng ghi cách dấu cách • Dịng 1: Ghi tổng số lượng mìn bãi • m dịng tiếp theo, dịng thứ i ghi n số hàng i đồ đánh dấu theo thứ tự từ trái qua phải Ví dụ: MINE.INP 10 15 03233 14355 14354 14244 13254 23233 23243 26452 46573 24442 Lê Minh Hoàng 5 5 5 3 4 2 3 4 4 4 6 3 5 3 5 4 2 4 5 4 4 5 1 3 MINE.OUT 80 10111 00100 00100 10111 10001 00001 01100 10101 01101 11111 1 1 0 0 0 0 1 1 0 0 1 0 1 1 1 1 1 1 1 0 1 1 0 0 1 0 1 1 1 1 0 1 1 1 0 1 44 Chuyên đề xét tới vấn đề thời gian việc xác định chi phí khác nhiều mơ hồ phức tạp Đối với người lập trình khác, thuật tốn với độ phức tạp dù thấp vô dụng cài đặt máy tính, bắt tay cài đặt thuật toán, ta phải biết cách tổ chức liệu cách khoa học, tránh lãng phí nhớ khơng cần thiết Có quy luật tương đối tổ chức liệu: Tiết kiệm nhớ thời gian thực thường chậm ngược lại Biết cân đối, dung hồ hai yếu tố kỹ cần thiết người lập trình Bài tập Bài Chứng minh cách chặt chẽ: Tại với P(n) đa thức bậc k giải thuật cấp O(P(n)) coi cấp O(nk) Bài Xác định độ phức tạp tính tốn giải thuật sau ký pháp chữ O lớn: a) Đoạn chương trình tính tổng hai đa thức: P(x) = amxm + am-1xm-1 + … + a1x + a0 Q(x) = bnxn + an-1xn-1 + … + b1x + b0 Để đa thức R(x) = cpxp + cp-1xp-1 + … + c1x + c0 if m < n then p := m else p := n; {p = min(m, n)} for i := to p c[i] := a[i] + b[i]; if p < m then for i := p + to m c[i] := a[i] else for i := p + to n c[i] := b[i]; while (p > 0) and (c[p] = 0) p := p - 1; b) Đoạn chương trình tính tích hai đa thức: P(x) = amxm + am-1xm-1 + … + a1x + a0 Q(x) = bnxn + an-1xn-1 + … + b1x + b0 Để đa thức R(x) = cpxp + cp-1xp-1 + … + c1x + c0 p := m + n; for i := to p for i := to m for j := to c[i + j] := c[i] := 0; n c[i + j] + a[i] * b[j]; Đại học Sư phạm Hà Nội, 1999-2002 Cấu trúc liệu Giải thuật 45 §3 ĐỆ QUY VÀ GIẢI THUẬT ĐỆ QUY 3.1 KHÁI NIỆM VỀ ĐỆ QUY Ta nói đối tượng đệ quy định nghĩa qua đối tượng khác dạng với quy nạp Ví dụ: Đặt hai gương cầu đối diện Trong gương thứ chứa hình gương thứ hai Chiếc gương thứ hai lại chứa hình gương thứ nên tất nhiên chứa lại hình ảnh gương thứ nhất… Ở góc nhìn hợp lý, ta thấy dãy ảnh vô hạn hai gương Một ví dụ khác người ta phát hình trực tiếp phát viên ngồi bên máy vô tuyến truyền hình, hình máy lại có hình ảnh phát viên ngồi bên máy vơ tuyến truyền hình thế… Trong tốn học, ta hay gặp định nghĩa đệ quy: Giai thừa n (n!): Nếu n = n! = 1; n > n! = n.(n-1)! Ký hiệu số phần tử tập hợp hữu hạn S |S|: Nếu S = ∅ |S| = 0; Nếu S ≠ ∅ tất có phần tử x ∈ S, |S| = |S\{x}| + Đây phương pháp định nghĩa tập số tự nhiên 3.2 GIẢI THUẬT ĐỆ QUY Nếu lời giải toán P thực lời giải tốn P' có dạng giống P lời giải đệ quy Giải thuật tương ứng với lời giải gọi giải thuật đệ quy Mới nghe lạ điểm mấu chốt cần lưu ý là: P' có dạng giống P, theo nghĩa đó, phải "nhỏ" P, dễ giải P việc giải khơng cần dùng đến P Trong Pascal, ta thấy nhiều ví dụ hàm thủ tục có chứa lời gọi đệ quy tới nó, bây giờ, ta tóm tắt lại phép đệ quy trực tiếp tương hỗ viết nào: Định nghĩa hàm đệ quy hay thủ tục đệ quy gồm hai phần: Phần neo (anchor): Phần thực mà công việc q đơn giản, giải trực tiếp khơng cần phải nhờ đến toán Phần đệ quy: Trong trường hợp toán chưa thể giải phần neo, ta xác định toán gọi đệ quy giải toán Khi có lời giải (đáp số) tốn phối hợp chúng lại để giải toán quan tâm Phần đệ quy thể tính "quy nạp" lời giải Phần neo quan trọng định tới tính hữu hạn dừng lời giải Lê Minh Hoàng 46 Chuyên đề 3.3 VÍ DỤ VỀ GIẢI THUẬT ĐỆ QUY 3.3.1 Hàm tính giai thừa function Factorial(n: Integer): Integer; {Nhận vào số tự nhiên n trả n!} begin if n = then Factorial := {Phần neo} else Factorial := n * Factorial(n - 1); {Phần đệ quy} end; Ở đây, phần neo định nghĩa kết hàm n = 0, phần đệ quy (ứng với n > 0) định nghĩa kết hàm qua giá trị n giai thừa n - Ví dụ: Dùng hàm để tính 3!, trước hết phải tính 2! 3! tính tích * 2! Tương tự để tính 2!, lại tính 1! 2! tính * 1! Áp dụng bước quy nạp thêm lần nữa, 1! = * 0!, ta đạt tới trường hợp phần neo, đến từ giá trị 0!, tính 1! = 1*1 = 1; từ giá trị 1! tính 2!; từ giá trị 2! tính 3!; cuối cho kết 6: 3! = * 2! ↓ 2! = * 1! ↓ 1! = * 0! ↓ 0! = 3.3.2 Dãy số Fibonacci Dãy số Fibonacci bắt nguồn từ toán cổ việc sinh sản cặp thỏ Bài toán đặt sau: 1) Các thỏ không chết 2) Hai tháng sau đời, cặp thỏ sinh cặp thỏ (một đực, cái) 3) Khi sinh tháng chúng lại sinh cặp Giả sử từ đầu tháng có cặp đời đến tháng thứ n có cặp Ví dụ, n = 5, ta thấy: Giữa tháng thứ 1: cặp (ab) (cặp ban đầu) Giữa tháng thứ 2: cặp (ab) (cặp ban đầu chưa đẻ) Giữa tháng thứ 3: cặp (AB)(cd) (cặp ban đầu đẻ thêm cặp con) Giữa tháng thứ 4: cặp (AB)(cd)(ef) (cặp ban đầu tiếp tục đẻ) Giữa tháng thứ 5: cặp (AB)(CD)(ef)(gh)(ik) (cả cặp (AB) (CD) đẻ) Bây giờ, ta xét tới việc tính số cặp thỏ tháng thứ n: F(n) Nếu cặp thỏ tháng thứ n - sinh cặp thỏ số cặp thỏ tháng thứ n là: F(n) = * F(n - 1) Đại học Sư phạm Hà Nội, 1999-2002 Cấu trúc liệu Giải thuật 47 Nhưng vấn đề vậy, cặp thỏ tháng thứ n - 1, có cặp thỏ có tháng thứ n - sinh tháng thứ n thơi Do F(n) = F(n - 1) + F(n - 2) (= số cũ + số sinh ra) Vậy tính F(n) theo công thức sau: F(n) = n ≤ F(n) = F(n - 1) + F(n - 2) n > function F(n: Integer): Integer; {Tính số cặp thỏ tháng thứ n} begin if n ≤ then F := {Phần neo} else F := F(n - 1) + F(n - 2); {Phần đệ quy} end; 3.3.3 Giả thuyết Collatz Collatz đưa giả thuyết rằng: với số nguyên dương X, X chẵn ta gán X := X div 2; X lẻ ta gán X := X * + Thì sau số hữu hạn bước, ta có X = Ví du: X = 10, bước tiến hành sau: X X X X X X = = = = = = 10 (chẵn) (lẻ) 16 (chẵn) (chẵn) (chẵn) (chẵn) ⇒ ⇒ ⇒ ⇒ ⇒ ⇒ X X X X X X := := := := := := 10 div 2; * + 1; 16 div 2; div div 2 div (5) (16) (8) (4) (2) (1) Cứ cho giả thuyết Collatz đắn, vấn đề đặt là: Cho trước số với hai phép toán * div 3, sử dụng cách hợp lý hai phép tốn để biến số thành giá trị nguyên dương X cho trước Ví dụ: X = 10 ta có * * * * div * = 10 Dễ thấy lời giải toán gần thứ tự ngược phép biến đổi Collatz: Để biểu diễn số X > biểu thức bắt đầu số hai phép toán "* 2", "div 3" Ta chia hai trường hợp: Nếu X chẵn, ta tìm cách biểu diễn số X div viết thêm phép toán * vào cuối Nếu X lẻ, ta tìm cách biểu diễn số X * + viết thêm phép toán div vào cuối procedure Solve(X: Integer); {In cách biểu diễn số X} begin if X = then Write(X) {Phần neo} else {Phần đệ quy} if X mod = then {X chẵn} begin Solve(X div 2); {Tìm cách biểu diễn số X div 2} Write(' * 2'); {Sau viết thêm phép tốn * 2} end else {X lẻ} begin Solve(X * + 1); {Tìm cách biểu diễn số X * + 1} Write(' div 3'); {Sau viết thêm phép toán div 3} end; end; Trên cách viết đệ quy trực tiếp, cịn có cách viết đệ quy tương hỗ sau: procedure Solve(X: Integer); forward; {Thủ tục tìm cách biểu diễn số X: Khai báo trước, đặc tả sau} Lê Minh Hoàng 48 Chuyên đề procedure SolveOdd(X: Integer); {Thủ tục tìm cách biểu diễn số X > trường hợp X lẻ} begin Solve(X * + 1); Write(' div 3'); end; procedure SolveEven(X: Integer); {Thủ tục tìm cách biểu diễn số X trường hợp X chẵn} begin Solve(X div 2); Write(' * 2'); end; procedure Solve(X: Integer); {Phần đặc tả thủ tục Solve khai báo trước trên} begin if X = then Write(X) else if X mod = then SolveOdd(X) else SolveEven(X); end; Trong hai cách viết, để tìm biểu diễn số X theo yêu cầu cần gọi Solve(X) xong Tuy nhiên cách viết đệ quy trực tiếp, thủ tục Solve có lời gọi tới nó, cịn cách viết đệ quy tương hỗ, thủ tục Solve chứa lời gọi tới thủ tục SolveOdd SolveEven, hai thủ tục lại chứa lời gọi ngược thủ tục Solve Đối với toán nêu trên, việc thiết kế giải thuật đệ quy tương ứng thuận lợi hai thuộc dạng tính giá trị hàm mà định nghĩa quy nạp hàm xác định dễ dàng Nhưng lúc phép giải đệ quy nhìn nhận thiết kế dễ dàng Thế vấn đề cần lưu tâm phép giải đệ quy? Có thể tìm thấy câu trả lời qua việc giải đáp câu hỏi sau: Có thể định nghĩa tốn dạng phối hợp toán loại nhỏ hay không ? Khái niệm "nhỏ hơn" ? Trường hợp đặc biệt toán coi trường hợp tầm thường giải để đưa vào phần neo phép giải đệ quy 3.3.4 Bài toán Tháp Hà Nội Đây tốn mang tính chất trị chơi, tương truyền ngơi đền Benares có ba cọc kim cương Khi khai sinh giới, thượng đế đặt n đĩa vàng chồng lên theo thứ tự giảm dần đường kính tính từ lên, đĩa to đặt cọc Đại học Sư phạm Hà Nội, 1999-2002 Cấu trúc liệu Giải thuật 49 Hình 5: Tháp Hà Nội Các nhà sư chuyển đĩa sang cọc khác theo luật: • Khi di chuyển đĩa, phải đặt vào ba cọc cho • Mỗi lần chuyển đĩa phải đĩa • Tại vị trí, đĩa chuyển đến phải đặt lên • Đĩa lớn không phép đặt lên đĩa nhỏ (hay nói cách khác: đĩa đặt cọc đặt đĩa lớn hơn) Ngày tận đến toàn chồng đĩa chuyển sang cọc khác Trong trường hợp có đĩa, cách làm mơ tả sau: Chuyển đĩa nhỏ sang cọc 3, đĩa lớn sang cọc chuyển đĩa nhỏ từ cọc sang cọc Những người bắt đầu giải toán cách dễ dàng số đĩa ít, họ gặp nhiều khó khăn số đĩa nhiều Tuy nhiên, với tư quy nạp tốn học máy tính cơng việc trở nên dễ dàng: Có n đĩa • Nếu n = ta chuyển đĩa từ cọc sang cọc xong • Giả sử ta có phương pháp chuyển n - đĩa từ cọc sang cọc 2, cách chuyển n - đĩa từ cọc x sang cọc y (1 ≤ x, y ≤ 3) tương tự • Giả sử ràng ta có phương pháp chuyển n - đĩa hai cọc Để chuyển n đĩa từ cọc x sang cọc y, ta gọi cọc lại z (=6 - x - y) Coi đĩa to … cọc, chuyển n - đĩa lại từ cọc x sang cọc z, sau chuyển đĩa to sang cọc y cuối lại coi đĩa to cọc, chuyển n - đĩa cịn lại cọc z sang cọc y chồng lên đĩa to Cách làm thể thủ tục đệ quy đây: procedure Move(n, x, y: Integer); {Thủ tục chuyển n đĩa từ cọc x sang cọc y} begin if n = then WriteLn('Chuyển đĩa từ ', x, ' sang ', y) else {Để chuyển n > đĩa từ cọc x sang cọc y, ta chia làm công đoạn} begin Move(n - 1, x, - x - y); {Chuyển n - đĩa từ cọc x sang cọc trung gian} Move(1, x, y); {Chuyển đĩa to từ x sang y} Move(n - 1, - x - y, y); {Chuyển n - đĩa từ cọc trung gian sang cọc y} end; end; Chương trình đơn giản, gồm có việc: Nhập vào số n gọi Move(n, 1, 2) Lê Minh Hoàng 50 Chuyên đề 3.4 HIỆU LỰC CỦA ĐỆ QUY Qua ví dụ trên, ta thấy đệ quy cơng cụ mạnh để giải tốn Có tốn mà bên cạnh giải thuật đệ quy có giải thuật lặp đơn giản hữu hiệu Chẳng hạn tốn tính giai thừa hay tính số Fibonacci Tuy vậy, đệ quy có vai trị xứng đáng nó, có nhiều tốn mà việc thiết kế giải thuật đệ quy đơn giản nhiều so với lời giải lặp số trường hợp chương trình đệ quy hoạt động nhanh chương trình viết khơng có đệ quy Giải thuật cho Tháp Hà Nội thuật toán xếp kiểu phân đoạn (QuickSort) mà ta nói tới sau ví dụ Có mối quan hệ khăng khít đệ quy quy nạp toán học Cách giải đệ quy cho toán dựa việc định rõ lời giải cho trường hợp suy biến (neo) thiết kế để lời giải toán suy từ lời giải toán nhỏ loại Tương tự vậy, quy nạp tốn học chứng minh tính chất ứng với số tự nhiên cách chứng minh tính chất với số trường hợp sở (thường người ta chứng minh với hay với 1) sau chứng minh tính chất với n với số tự nhiên nhỏ n Do ta khơng lấy làm ngạc nhiên thấy quy nạp toán học dùng để chứng minh tính chất có liên quan tới giải thuật đệ quy Chẳng hạn: Chứng minh số phép chuyển đĩa để giải toán Tháp Hà Nội với n đĩa 2n-1: Rõ ràng tính chất với n = 1, ta cần 21 - = lần chuyển đĩa để thực yêu cầu Với n > 1; Giả sử để chuyển n - đĩa hai cọc ta cần 2n-1 - phép chuyển đĩa, để chuyển n đĩa từ cọc x sang cọc y, nhìn vào giải thuật đệ quy ta thấy trường hợp cần (2n-1 - 1) + + (2n-1 - 1) = 2n - phép chuyển đĩa Tính chất chứng minh với n Vậy cơng thức với n Thật đáng tiếc phải lập trình với cơng cụ khơng cho phép đệ quy, khơng có nghĩa ta bó tay trước tốn mang tính đệ quy Mọi giải thuật đệ quy có cách thay giải thuật không đệ quy (khử đệ quy), nói tất chương trình đệ quy trình dịch chuyển thành mã lệnh không đệ quy trước giao cho máy tính thực Việc tìm hiểu cách khử đệ quy cách "máy móc" chương trình dịch cần hiểu rõ chế xếp chồng thủ tục dây chuyền gọi đệ quy làm Nhưng muốn khử đệ quy cách tinh tế phải tuỳ thuộc vào toán mà khử đệ quy cho khéo Khơng phải tìm đâu xa, kỹ thuật giải công thức truy hồi quy hoạch Đại học Sư phạm Hà Nội, 1999-2002 Cấu trúc liệu Giải thuật 51 động ví dụ cho thấy tính nghệ thuật cách tiếp cận toán mang chất đệ quy để tìm giải thuật khơng đệ quy đầy hiệu Bài tập Bài Viết hàm đệ quy tính ước số chung lớn hai số tự nhiên a, b không đồng thời 0, rõ đâu phần neo, đâu phần đệ quy Bài Viết hàm đệ quy tính C k theo cơng thức truy hồi sau: n C0 = Cn = n n Với < k < n: C k = C k −1 + C k −1 n n −1 n Chứng minh hàm cho giá trị C k = n n! k!(n − k )! Bài Nêu rõ bước thực giải thuật cho Tháp Hà Nội trường hợp n = Viết chương trình giải tốn Tháp Hà Nội khơng đệ quy Lê Minh Hồng 52 Chun đề §4 CẤU TRÚC DỮ LIỆU BIỂU DIỄN DANH SÁCH 4.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, xoá phần tử khỏi danh sách, xếp lại phần tử danh sách theo trật tự v.v… 4.2 BIỂU DIỄN DANH SÁCH TRONG MÁY TÍNH 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 để 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 danh sách 4.2.1 Cài đặt mảng chiều Khi cài đặt danh sách mảng, có biến nguyên n lưu số phần tử có danh sách Nếu mảng đánh số phần tử danh sách cất giữ mảng phần tử đánh số từ tới n Chèn phần tử vào mảng: Mảng ban đầu: p A B C D E F G H I J K L Nếu muốn chèn phần tử V vào mảng vị trí p, ta phải: Dồn tất phần tử từ vị trí p tới tới vị trí n sau vị trí: p A B C D E F G H I J K L G H I J K L H I J K L Đặt giá trị V vào vị trí p: p A B C D E F V Tăng n lên Xoá phần tử khỏi mảng Mảng ban đầu: p A B C D E F G Muốn xoá phần tử thứ p mảng mà giữ nguyên thứ tự phần tử lại, ta phải: Dồn tất phần tử từ vị trí p + tới vị trí n lên trước vị trí: Đại học Sư phạm Hà Nội, 1999-2002 Cấu trúc liệu Giải thuật 53 p A B C D E F H I J K L I J K L Giảm n p A B C D E F H 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 đảo giá trị phần tử cần xóa cho phần tử cuối giảm số phần tử mảng (n) 4.2.2 Cài đặt danh sách nối đơn Danh sách nối đơn gồm nút nối với theo chiều Mỗi nút ghi (record) gồm hai trường: Trường thứ chứa giá trị lưu nút Trường thứ hai 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 gán giá trị đặc biệt Data Giá trị Liên kết Hình 6: Cấu trúc nút danh sách nối đơn Nút danh sách gọi chốt danh sách nối đơn (Head) Để duyệt danh sách nối đơn, ta chốt, dựa vào trường liên kết để 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 Head A B C D E Hình 7: Danh sách nối đơn Chèn phần tử vào danh sách nối đơn: Danh sách ban đầu: Head A B C D q p Muốn chèn thêm nút chứa giá trị V vào vị trí nút p, ta phải: Lê Minh Hoàng E 54 Chuyên đề a) Tạo nút NewNode chứa giá trị V: V b) Tìm nút q nút đứng trước nút p danh sách (nút có liên kết tới p) b1) Nếu tìm thấy chỉnh lại liên kết: q liên kết tới NewNode, NewNode liên kết tới p Head B C D q A E p V b2) Nếu khơng có nút đứng trước nút p danh sách tức p = Head, ta chỉnh lại liên kết: NewNode liên kết tới Head (cũ) đặt lại Head = NewNode Xoá phần tử khỏi danh sách nối đơn: Danh sách ban đầu: Head A B C D q E p Muốn huỷ nút p khỏi danh sách nối đơn, ta phải: Tìm nút q nút đứng liền trước nút p danh sách (nút có liên kết tới p) Nếu tìm thấy chỉnh lại liên kết: q liên kết thẳng tới nút liền sau p, q trình duyệt danh sách Head duyệt tới q nhảy qua không duyệt p Trên thực tế cài đặt biến động trỏ, ta nên có thao tác giải phóng nhớ cấp cho nút p Head A B C D q E p Nếu nút đứng trước nút p danh sách tức p = Head, ta việc đặt lại Head nút đứng Head (cũ) danh sách Sau giải phóng nhớ cấp cho nút p (Head cũ) 4.2.3 Cài đặt danh sách nối kép Danh sách nối kép gồm nút nối với theo hai chiều Mỗi nút ghi (record) gồm ba trường: Đại học Sư phạm Hà Nội, 1999-2002 Cấu trúc liệu Giải thuật 55 • Trường thứ chứa giá trị lưu nút • Trường thứ hai (Next) 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 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 gán giá tị đặc biệt • Trường thứ ba (Prev) chứa liên kết (con trỏ) tới nút liền trước, tức chứa thông tin đủ để biết nút đứng trước nút danh sách nút nào, trường hợp nút (khơng có nút liền trước) trường gán giá trị đặc biệt Liên kết sau Data Giá trị Liên kết trước Hình 8: Cấu trúc nút danh sách nối kép Khác với danh sách nối đơn, danh sách nối kép có hai chốt: Nút danh sách gọi First, nút cuối danh sách gọi Last Để duyệt danh sách nối kép, ta có hai cách: Hoặc First, dựa vào liên kết Next để 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 Hoặc Last, dựa vào liên kết Prev để sang nút liền trước, đến gặp giá trị đặc biệt (duyệt qua nút đầu) dừng lại First A B C D E Last Hình 9: Danh sách nối kép Việc chèn / xoá vào danh sách nối kép đơn giản kỹ thuật chỉnh lại mối liên kết nút cho hợp lý, ta coi tập 4.2.4 Cài đặt danh sách nối vòng hướng Trong danh sách nối đơn, phần tử cuối danh sách có trường liên kết gán giá trị đặc biệt (thường sử dụng giá trị nil) Nếu ta cho trường liên kết phần tử cuối trỏ thẳng phần tử danh sách ta kiểu danh sách gọi danh sách nối vòng hướng A B C D Hình 10: Danh sách nối vịng hướng Lê Minh Hoàng E 56 Chuyên đề Đối với danh sách nối vòng, ta cần biết nút danh sách ta duyệt hết nút danh sách cách theo hướng liên kết Chính lý này, chèn xố vào danh sách nối vịng, ta xử lý trường hợp riêng chèn xố vị trí chốt 4.2.5 Cài đặt danh sách nối vòng hai hướng Danh sách nối vòng hướng cho ta duyệt nút danh sách theo chiều, cài đặt danh sách nối vịng hai hướng ta duyệt nút danh sách theo chiều ngược lại Danh sách nối vịng hai hướng tạo thành từ danh sách nối kép ta cho trường Prev nút First trỏ thẳng tới nút Last trường Next nút Last trỏ thẳng nút First A B C D E Hình 11: Danh sách nối vịng hai hướng Bài tập Bài Lập chương trình quản lý danh sách học sinh, tuỳ chọn loại danh sách cho phù hợp, chương trình có chức sau: (Hồ sơ học sinh giả sử có: Tên, lớp, số điện thoại, điểm TB …) Cho phép nhập danh sách học sinh từ bàn phím hay từ file Cho phép in danh sách học sinh gồm có tên xếp loại Cho phép in danh sách học sinh gồm thông tin đầy đủ Cho phép nhập vào từ bàn phím tên học sinh tên lớp, tìm xem có học sinh có tên nhập vào lớp khơng ? Nếu có in số điện thoại học sinh Cho phép vào hồ sơ học sinh từ bàn phím, bổ sung học sinh vào danh sách học sinh, in danh sách Cho phép nhập vào từ bàn phím tên lớp, loại bỏ tất học sinh lớp khỏi danh sách, in danh sách Có chức xếp danh sách học sinh theo thứ tự giảm dần điểm trung bình Cho phép nhập vào hồ sơ học sinh từ bàn phím, chèn học sinh vào danh sách mà không làm thay đổi thứ tự xếp, in danh sách Cho phép lưu trữ lại đĩa danh sách học sinh thay đổi Đại học Sư phạm Hà Nội, 1999-2002 Cấu trúc liệu Giải thuật 57 Bài Có n người đánh số từ tới n ngồi quanh vòng tròn (n ≤ 10000), chơi trò chơi: Một người đếm 1, người kế tiếp, theo chiều kim đồng hồ đếm 2… người đếm đến số nguyên tố phải khỏi vòng tròn, người lại đếm 1: Hãy lập chương trình Nhập vào số n S từ bàn phím • Cho biết người thứ người đếm người lại cuối vòng tròn người thứ • Cho biết người cịn lại cuối vịng trịn người thứ k người đếm người nào? Giải hai yêu cầu trường hợp: trò chơi đếm theo chiều kim đồng hồ, có người bị khỏi chơi người đếm trình đếm ngược lại (tức ngược chiều kim đồng hồ) Lê Minh Hoàng 58 Chuyên đề §5 NGĂN XẾP VÀ HÀNG ĐỢI 5.1 NGĂN XẾP (STACK) Ngăn xếp kiểu danh sách trang bị hai phép toán bổ sung phần tử vào cuối danh sách loại bỏ phần tử cuối danh sách Có thể hình dung ngăn xếp hình ảnh chồng đĩa, đĩa đặt vào chồng sau nằm tất đĩa khác lấy Vì ngun tắc"vào sau trước" đó, Stack cịn có tên gọi danh sách kiểu LIFO (Last In First Out) vị trí cuối danh sách gọi đỉnh (Top) Stack 5.1.1 Mô tả Stack mảng Khi mô tả Stack mảng: Việc bổ sung phần tử vào Stack tương đương với việc thêm phần tử vào cuối mảng Việc loại bỏ phần tử khỏi Stack tương đương với việc loại bỏ phần tử cuối mảng Stack bị tràn bổ sung vào mảng đầy Stack rỗng số phần tử thực chứa mảng = program StackByArray; const max = 10000; var Stack: array[1 max] of Integer; Last: Integer; procedure StackInit; {Khởi tạo Stack rỗng} begin Last := 0; end; procedure Push(V: Integer); {Đẩy giá trị V vào Stack} begin if Last = max then WriteLn('Stack is full') {Nếu Stack đầy khơng đẩy thêm vào nữa} else begin Inc(Last); Stack[Last] := V; {Nếu khơng thêm phần tử vào cuối mảng} end; end; function Pop: Integer; {Lấy giá trị khỏi Stack, trả kết hàm} begin if Last = then WriteLn('Stack is empty') {Stack rỗng khơng lấy được} else begin Pop := Stack[Last]; Dec(Last); {Lấy phần tử cuối khỏi mảng} end; end; begin StackInit; ; {Đưa vài lệnh để kiểm tra hoạt động Stack} Đại học Sư phạm Hà Nội, 1999-2002 ... tự từ trái qua phải Ví dụ: MINE.INP 10 15 0 323 3 14355 14354 1 424 4 1 325 4 23 233 23 243 26 4 52 46573 24 4 42 Lê Minh Hoàng 5 5 5 3 4 2 3 4 4 4 6 3 5 3 5 4 2 4 5 4 4 5 1 3 MINE.OUT 80 10111 00100 00100... nhận e) Không phải lúc giải thuật cấp O(n2) tốt giải thuật cấp O(n3) Bởi giải thuật cấp O(n2) có thời gian thực 1000n2, giải thuật cấp O(n3) lại cần thời Lê Minh Hoàng 42 Chuyên đề gian thực n3,... tâm mà tập trung giải phần khác Đại học Sư phạm Hà Nội, 199 9 -2 0 02 Cấu trúc liệu Giải thuật 37 1.4 LẬP TRÌNH Sau có thuật tốn, ta phải tiến hành lập trình thể thuật tốn Muốn lập trình đạt hiệu cao,

Ngày đăng: 13/08/2014, 20:22

Từ khóa liên quan

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

Tài liệu liên quan