Tài liệu hạn chế xem trước, để xem đầy đủ mời bạn chọn Tải xuống
1
/ 134 trang
THÔNG TIN TÀI LIỆU
Thông tin cơ bản
Định dạng
Số trang
134
Dung lượng
2,46 MB
Nội dung
Chương I KỸ THUẬT THIẾT KẾ THUẬT TOÁN “It is not the strongest of the species that survives, nor the most intelligent that survives It is the one that is the most adaptable to change” Charles Darwin Chương giới thiệu số kỹ thuật quan trọng việc tiếp cận tốn tìm thuật tốn Các lớp thuật toán thảo luận chương là: Vét cạn (exhaustive search), Chia để trị (divide and conquer), Quy hoạch động (dynamic programming) Tham lam (greedy) Các tốn thực có mn hình mn vẻ, khơng thể đưa cách thức chung để tìm giải thuật cho toán Các phương pháp “chiến lược” kinh điển Khác với thuật toán cụ thể mà biết QuickSort, tìm kiếm nhị phân,…, vấn đề chương học theo kiểu “thuộc cài đặt”, khơng thể tìm thấy thuật tốn thư viện lập trình Chúng ta khảo sát vài tốn cụ thể học cách nghĩ, cách tiếp cận vấn đề, cách thiết kế giải thuật Từ rèn luyện kỹ linh hoạt giải toán thực tế Bài Liệt kê Có số tốn thực tế yêu cầu rõ: tập đối tượng cho trước có đối tượng thoả mãn điều kiện định đối tượng Bài toán gọi toán liệt kê hay toán duyệt Nếu ta biểu diễn đối tượng cần tìm dạng cấu hình biến số để giải tốn liệt kê, cần phải xác định thuật toán để theo xây dựng tất cấu hình quan tâm Có nhiều phương pháp liệt kê, chúng cần phải đáp ứng hai yêu cầu đây: Không lặp lại cấu hình Khơng bỏ sót cấu hình Trước nói thuật tốn liệt kê, giới thiệu số khái niệm bản: 1.1 Vài khái niệm 1.1.1 Thứ tự từ điển Nhắc lại quan hệ thứ tự toàn phần “nhỏ bằng” ký hiệu “” tập hợp , quan hệ hai thoả mãn bốn tính chất: Với Tính phổ biến (Universality): Hoặc Tính phản xạ (Reflexivity): Tính phản đối xứng (Antisymmetry) : Nếu Tính bắc cầu (Transitivity): Nếu có Các quan hệ , và tự suy từ quan hệ ; bắt buộc Trên dãy hữu hạn, người ta xác định quan hệ thứ tự: Xét hai dãy độ dài , phần tử phần “” Khi có quan hệ thứ tự toàn : Hoặc hai dãy giống nhau: Hoặc tồn số nguyên dương để Thứ tự gọi thứ tự từ điển (lexicographic order) dãy độ dài Khi hai dãy có số phần tử khác nhau, người ta xác định thứ tự từ điển Bằng cách thêm vào cuối dãy dãy nhau, coi phần tử phần tử đặc biệt gọi để độ dài nhỏ tất phần tử khác, ta lại đưa xác định thứ tự từ điển hai dãy độ dài Ví dụ: ( ) ( ( ) ( ) ) calculato computer Thứ tự từ điển quan hệ thứ tự toàn phần dãy 1.1.2 Chỉnh hợp, tổ hợp, hoán vị Cho tập hữu hạn gồm phần tử số tự nhiên Gọi tập số nguyên dương từ tới : Chỉnh hợp lặp Một ánh xạ phần tử ( ) cho tương ứng phần tử , gọi chỉnh hợp lặp chập Do tập hữu hạn ( ( ( ) ( ) phần tử) nên ánh xạ ( )), ta đồng xác định qua bảng giá trị với dãy giá trị ( ( ) ( ) ( )) coi dãy giá trị chỉnh hợp lặp chập Ví dụ Một ánh xạ cho bởi: () tương ứng với tập ảnh ( ) chỉnh hợp lặp Số chỉnh hợp lặp chập tập phần tử Chỉnh hợp không lặp Mỗi đơn ánh gọi chỉnh hợp khơng lặp chập Nói cách khác, chỉnh hợp khơng lặp chỉnh hợp lặp có phần tử khác đơi Ví dụ chỉnh hợp không lặp chập ( ) tập () Số chỉnh hợp không lặp chập tập phần tử ( ) Hoán vị Khi song ánh gọi hoán vị Nói cách khác hốn vị chỉnh hợp khơng lặp chập Ví dụ: ( ) hoán vị () Số hoán vị tập phần tử Tổ hợp Mỗi tập gồm phần tử gọi tổ hợp chập Lấy tổ hợp chập không lặp chập , xét tất hốn vị nó, hốn vị chỉnh hợp Điều tức liệt kê tất chỉnh hợp khơng lặp chập tổ hợp chập tính Số tổ hợp chập tập lần Như xét mặt số lượng: phần tử ( ) ( ) Ta có cơng thức khai triển nhị thức: ( ) ∑( ) Vì số ( ) gọi hệ số nhị thức (binomial coefficient) thứ , bậc 1.2 Phương pháp sinh Phương pháp sinh áp dụng để giải tốn liệt kê hai điều kiện sau thoả mãn: Có thể xác định thứ tự tập cấu hình tổ hợp cần liệt kê Từ biết cấu hình cấu hình cuối theo thứ tự Xây dựng thuật tốn từ cấu hình chưa phải cấu hình cuối, sinh cấu hình 1.2.1 Mơ hình sinh Phương pháp sinh viết mơ hình chung: «Xây dựng cấu hình đầu tiên»; repeat «Đưa cấu hình có»; «Từ cấu hình có sinh cấu hình cịn»; until «hết cấu hình»; 1.2.2 Liệt kê dãy nhị phân độ dài Một dãy nhị phân độ dài dãy Có thể nhận thấy dãy nhị phân biểu diễn nhị phân giá trị nguyên ( ) ) Số dãy nhị phân độ dài , thứ tự từ điển ( ) ( dãy nhị phân độ dài tương đương với quan hệ thứ tự giá trị số mà chúng biểu diễn Vì vậy, liệt kê dãy nhị phân theo thứ tự từ điển nghĩa phải dãy nhị phân biểu diễn số nguyên theo thứ tự Ví dụ với , có dãy nhị phân độ dài liệt kê: ( ) 000 001 010 011 Theo thứ tự liệt kê, dãy ⏟ 100 101 110 111 dãy cuối ⏟ Nếu ta có dãy nhị phân độ dài , ta sinh dãy nhị phân cách cộng thêm (theo số có nhớ) vào dãy 10101111 + ──────── 10110000 Dựa vào tính chất phép cộng hai số nhị phân, cấu hình sinh từ cấu hình cách: xét từ cuối dãy lên đầu day (xet từ hàng đơn vị lên), tìm số gặp đầu tiên… Nếu thấy thay số số đặt tất phần tử phía sau vị trí Nếu khơng thấy thì tồn dãy số 1, cấu hình cuối Input Số nguyên dương Output Các dãy nhị phân độ dài Sample Input Sample Output 000 001 010 011 100 101 110 111 BINARYSTRINGS_GEN.PAS Thuật toán sinh liệt kê dãy nhị phân {$MODE OBJFPC} program BinaryStringEnumeration; var x: AnsiString; n, i: Integer; begin ReadLn(n); SetLength(x, n); FillChar(x[1], n, '0'); //Cấu hình ban đầu x=00 repeat WriteLn(x); //Tìm số từ cuối dãy i := n; while (i > 0) and (x[i] = '1') Dec(i); if i > then u tìm thấ begin x[i] := '1'; i b ng số if i < n then t i n FillChar(x[i + 1], n - i, '0'); end else Break; h ng tìm thấ số n o ừng until False; end 1.2.3 Liệt kê tập có phần tử Ta lập chương trình liệt kê tập phần tử tập theo thứ tự từ đien Ví dụ: , có 10 tập con: {1, 2, 3} {1, 2, 4} {1, 2, 5} {1, 3, 4} {1, 3, 5} {1, 4, 5} {2, 3, 4} {2, 3, 5} {2, 4, 5} {3, 4, 5} Bài toán liệt kê tập dãy phần tử phần tử tập quy toán liệt kê , Nếu xếp dãy theo thứ tự từ điển, ta nhận thấy: Tập (cấu hình khởi tạo) Tap cuoi cung (cấu hình kết thúc) et mot tap , ta có nhận xét giới hạn (giá trị lớn nhận) quát: giới hạn la n, , … Tổng Còn tất nhiên, giới hạn (gia tri nho nhat co the nhan) Tư mot day la đai dien cho mot tap cua S, neu tất phần tử x đạt tới giới hạn tren th x la cau h nh cuoi cung, khơng ta phải sinh dãy tăng dần thoả man: day mơi vừa đủ lớn dãy cũ theo nghĩa day k phần tử chen chúng thứ tự từ điển Ví dụ: Cấu hình có ( ) Các phần tử đạt tới giới hạn trên, nên để sinh cấu hình ta sinh cách tăng phần tử số cac phan tư ( hình lên được, ta phải tăng lên đơn vị Được cấu ) Cấu hình lớn cấu hình trước chưa thoả mãn tính chất vừa đủ lớn Muốn t m cau h nh vưa đu lơn cau h nh cu, can co them thao tac: Thay cac gia tri giới hạn chung Tức là: Ta cấu hình lại nhận thấy ( cau h nh mơi ( ) cấu hình Tiep tuc vơi cau h nh nay, ta chưa đạt giới hạn trên, cần tăng ) Thuật toan sinh day từ day co xây dựng sau: Tìm từ cuối dãy lên đầu gặp phần tử chưa đạt giới hạn Tăng lên Đặt tất phần tử giới hạn cua chung Nếu khơng tìm thấy tức phần tử đạt giới hạn trên, cấu hình cuối Input Hai số nguyên dương ( ) Output Các tập k phần tử tập Sample Input … Nếu tìm thấy: lên Sample {1, 2, {1, 2, {1, 2, {1, 3, {1, 3, {1, 4, {2, 3, {2, 3, {2, 4, {3, 4, Output 3} 4} 5} 4} 5} 5} 4} 5} 5} 5} SUBSETS_GEN.PAS Thuật toán sinh liệt kê tập {$MODE OBJFPC} program SubSetEnumeration; const max = 100; var x: array[1 max] of Integer; n, k, i, j: Integer; begin ReadLn(n, k); for i := to k x[i] := i; repeat In cấu hình t i Write('{'); for i := to k begin h it o , , , phần tử Write(x[i]); if i < k then Write(', '); end; WriteLn('}'); u ệt từ cuối n tìm i ch a đ t giới h n tr n n – k + i i := k; while (i > 0) and (x[i] = n - k + i) Dec(i); if i > then u tìm thấ begin Inc(x[i]); ăng i n t i b ng giới h n ới ch ng for j := i + to k x[j] := x[j - 1] + 1; end else Break; until False; end 1.2.4 Liệt kê hốn vị Ta lập chương trình liệt kê hoán vị tập theo thứ tự từ điển Ví dụ với n = 3, có hốn vị: ( Mỗi hoán vị tập ) ( ) ( ) ( ) ( ) ( ) biểu diễn dạng một dãy số Theo thứ tự từ điển, ta nhận thấy: Hoán vị cần liệt kê: ( ) Hoán vị cuối cần liệt kê: ( Bắt đầu từ hoán vị ( ) ), ta sinh hốn vị cịn lại theo quy tắc: Hoán vị sinh phải hoán vị vừa đủ lớn hoán vị theo nghĩa khơng thể có hốn vị khác chen chúng thứ tự Giả sử hoán vị ( ), xét phần tử cuối cùng, ta thấy chúng xếp giảm dần, điều có nghĩa cho dù ta có hốn vị phần tử nào, ta hoán vị bé hoán vị Như ta phải xét đến thay giá trị khác Ta thay giá trị nào?, hoán vị nhỏ hơn, khơng thể có (phần tử sau không chọn vào giá trị mà phần tử trước chọn) Còn lại giá trị: 4, Vì cần hốn vị vừa đủ lớn nên ta chọn Còn giá trị lấy tập Cũng tính vừa đủ lớn nên ta tìm biểu diễn nhỏ số gán cho ( ) Vậy hoán vị ( ) tức Ta có nhận xét qua ví dụ này: Đoạn cuối hoán vị xếp giảm dần, số số nhỏ đoạn cuối giảm dần thoả mãn điều kiện lớn Nếu đảo ), đoạn cuối giá trị ta hoán vị ( xếp giảm dần Khi muốn biểu diễn nhỏ cho giá trị đoạn cuối ta cần đảo ngược đoạn cuối ) hốn vị ( Trong trường hợp hoán vị ( ) Ta có ) có đoạn cuối giảm dần, đoạn cuối gồm phần tử (4) thể coi hoán vị ( Thuật toán sinh hoán vị từ hốn vị xây dựng sau: ác định đoạn cuối giảm dần dài nhất, tìm số phần tử đứng liền trước đoạn cuối Điều đồng nghĩa với việc tìm từ vị trí sát cuối dãy lên đầu, gặp số thỏa mãn Nếu tìm thấy số Trong đoạn cuối giảm dần, tìm phần tử nhỏ vừa đủ lớn Do đoạn cuối giảm dần, điều thực cách tìm từ cuối dãy lên đầu gặp số thoả mãn (có thể dùng tìm kiếm nhị phân) Đảo giá trị Lật ngược thứ tự đoạn cuối giảm dần ( ), đoạn cuối trở thành tăng dần Nếu khơng tìm thấy tức toàn dãy giảm dần, cấu hình cuối Input Số ngun dương Output Các hốn vị dãy ( ) Sample Input Sample (1, 2, (1, 3, (2, 1, (2, 3, (3, 1, (3, 2, Output 3) 2) 3) 1) 2) 1) PERMUTATIONS_GEN.PAS Thuật toán sinh liệt kê hoán vị {$MODE OBJFPC} program PermutationEnumeration; const max = 100; var x: array[1 max] of Integer; n, i, k, l, h: Integer; //Thủ tục đảo giá trị hai tham bi n x, y procedure Swap(var x, y: Integer); var temp: Integer; begin temp := x; x := y; y := temp; end; begin ReadLn(n); for i := to n x[i] := i; repeat //In cấu hình t i Write('('); for i := to n begin Write(x[i]); if i < n then Write(', '); end; WriteLn(')'); //Sinh cấu hình k ti p //Tìm i số đứng tr ớc đo n cuối giảm dần i := n - 1; while (i > 0) and (x[i] > x[i + 1]) Dec(i); if i > then //N u tìm thấy begin //Tìm từ cuối dãy phần tử (x[k]) lớn i k := n; while x[k] < x[i] Dec(k); ảo giá trị x[k] x[i] Swap(x[k], x[i]); //Lật ng ợc thứ tự đo n cuối giảm dần, đo n cuối tr th nh tăng ần l := i + 1; h := n; while l < h begin Swap(x[l], x[h]); Inc(l); Dec(h); end; end else Break; //Cả dãy giảm dần, h t cấu hình until False; end Nhược điểm phương pháp sinh khơng thể sinh cấu hình thứ có cấu hình thứ chưa , điều làm phương pháp sinh tính phổ dụng thuật tốn duyệt hạn chế Hơn nữa, khơng phải cấu hình ban đầu lúc dễ tìm được, khơng phải kỹ thuật sinh cấu hình cho tốn đơn giản (Sinh chỉnh hợp khơng lặp chập theo thứ tự từ điển chẳng hạn) Ta sang chuyên mục sau nói đến phương pháp liệt kê có tính phổ dụng cao hơn, để giải tốn liệt kê phức tạp là: Thuật toán quay lui (Back tracking) 1.3 Thuật toán quay lui Thuật toán quay lui dùng để giải toán liệt kê cấu hình Thuật tốn làm việc theo cách: Mỗi cấu hình xây dựng cách xây dựng phần tử Mỗi phần tử chọn cách thử tất khả Giả sử cấu hình cần liệt kê có dạng nhận, thử cho xét tất giá trị , thuật tốn quay lui xét tất giá trị nhận giá trị Với giá trị thử gán cho nhận, lại thử cho , thuật toán nhận giá trị Với giá ( ) ( ) ( ) ( ) ( ( ) ( ) Từ suy ( ) ( ) Giả sử phản chứng ( ) với tần suất ( ) ( ( ) ( ) hay ( ) ( ) ) (4.3) ( )) ( ) ( ) anh-em (Bổ đề 4-4) Đưa ký tự vào nút cha chung ( ) cắt bỏ hai nút ̂ Ta ( ) ̂ tương ứng với mã phi tiền tố (̂ ) ( ) ( ) không tối ưu, gọi ̂ tối ưu tập ký tự Xét ̂ , khơng giảm tính tổng qt, coi ( ))( Trong đó: ( ̂) ( ) ( ) ( ) ( ) ( ) (do T khong toi ưu) (4.4) ( ) Vậy ( ̂ ) ( ), mâu thuẫn với giả thiết tối ưu tập ký tự Ta có điều phải chứng minh Tính đắn thuật tốn Huffman suy trực tiếp từ Định lý 4-5: Để tìm tối ưu tập ký tự , ta tìm hai ký tự có tần suất thấp ký tự Sau thiết lập quan hệ cha-con ưu tập có lực lượng nhập chúng lại thành , ta quy toán con: Tìm tối phần tử Cài đặt Chúng ta cài đặt chương trình tìm mã phi tiền tố tối ưu để mã hóa ký tự xâu ký tự đầu vào Input Xâu ký tự Output Các từ mã tương ứng với ký tự Sample Input abcdefabcdefabcdeabcdabdadaaaaaaaa Sample Output = a 100 = c 101 = b 1100 = f 1101 = e 111 = d 30 14 20 a 11 c b f d e Hàng đợi ưu tiên nút chương trình tổ chức dạng Binary Heap Trên ( ) để vun nhánh Heap gốc thành đống điều kiện ta cài đặt thao tác hai nhánh (gốc ) đống Tại bước thuật toán Huffman, thay cài đặt chế “ra hai vào một”, ta sử dụng mẹo nhỏ: Lấy khỏi Heap ( ) nút , đọc nút gốc Heap đè lên nút gốc Heap ( ), tạo nút cha chung ( ) thực vun đống từ gốc: HUFFMAN.PAS Mã hóa Huffman {$MODE OBJFPC} program HuffmanCode; const MaxLeaves = 256; //Các ký tự kiểu AnsiChar, cần đổi ích th ớc n u dùng kiểu liệu khác type TNode = record //Cấu trúc nút Huffman f: Integer; c: AnsiChar; l, r: Pointer; end; PNode = ^TNode; //Kiểu trỏ tới nút THeap = record //Cấu trúc liệu Binary Heap items: array[1 MaxLeaves] of PNode; nItems: Integer; end; var s: AnsiString; //Xâu ký tự đầu vào Heap: THeap; H ng đợi u ti n TreeRoot: PNode; //Gốc Huffman bits: array[1 MaxLeaves] of Integer; //T o nút chứa tần suất fq, ký tự ch, hai nhánh left, right function NewNode(fq: Integer; ch: AnsiChar; left, right: PNode): PNode; begin New(Result); with Result^ , đưa nút vào begin f:= fq; c := ch; l := left; r := right; end; end; ịnh nghĩa quan hệ u ti n quan hệ < n t u ti n n t n u tần suất x nhỏ operator < (const x, y: TNode): Boolean; begin Result := x.f < y.f; end; //Vun nhánh Heap gốc r th nh đống procedure Heapify(r: Integer); var c: Integer; temp: PNode; begin with Heap begin temp := items[r]; repeat c := r * 2; if (c < nItems) and (items[c + 1]^ < items[c]^) then Inc(c); if (c > nItems) or not (items[c]^ < temp^) then Break; items[r] := items[c]; r := c; until False; items[r] := temp; end; end; // ọc nút gốc Heap function Get: PNode; begin with Heap Result := items[1]; end; //Lấy nút có tần suất nhỏ khỏi Heap function Pop: PNode; begin with Heap begin Result := items[1]; items[1] := items[nItems]; Dec(nItems); Heapify(1); end; end; //Thay nút gốc Heap b i node procedure UpdateRootHeap(node: PNode); begin with Heap begin items[1] := node; Heapify(1); end; end; procedure InitHeap; //Kh i t o Heap ban đầu chứa nút var c: AnsiChar; i: Integer; freq: array[AnsiChar] of Integer; begin FillDWord(freq, Length(freq), 0); for i := to Length(s) Inc(freq[s[i]]); m tần suất with Heap begin nItems := 0; for c := Low(AnsiChar) to High(AnsiChar) if freq[c] > then //Xét ký tự S begin Inc(nItems); items[nItems] := NewNode(freq[c], c, nil, nil); //T o nút chứa ký tự end; for i := nItems div downto Vun đống từ ới lên Heapify(i); end; end; procedure BuildTree; //Thuật toán Huffman var x, y, z: PNode; begin while Heap.nItems > //Chừng Heap nhiều phần tử begin x := Pop; //Lấy nút tần suất nhỏ khỏi Heap y := Get; ọc nút tần suất nhỏ ti p theo gốc Heap z := NewNode(x^.f + y^.f, #0, x, y); //T o nút z cha x y UpdateRootHeap(z); a z v o gốc Heap thực vun đống: Ra x y, vào z end; TreeRoot := Heap.items[1]; //Giữ l i gốc Huffman end; //Thủ tục in từ mã Huffman gốc no e, epth độ sâu node procedure Traversal(node: PNode; depth: Integer); //Duyệt Huffman gốc node var i: Integer; begin if node^.l = nil then //N u node nút begin //In dãy bit biểu diễn ký tự for i := to depth Write(bits[i]); WriteLn(' = ', node^.c); Dispose(node); end else //N u node nút nhánh begin bits[depth + 1] := 0; //Các từ mã nhánh trái có bit ti p theo Traversal(node^.l, depth + 1); //Duyệt nhánh trái bits[depth + 1] := 1; //Các từ mã nhánh phải có bit ti p theo Traversal(node^.r, depth + 1); //Duyệt nhánh phải end; end; begin ReadLn(s); InitHeap; BuildTree; Traversal(TreeRoot, 0); end Xét riêng thuật toán Huffman thủ tục BuildTree Ta thấy số ký tự (số nút Huffman) vịng lặp while lặp lần Các lời gọi thủ tục bên vịng lặp ) Vậy thuật tốn Huffman có thời gian thực ( ) có thời gian thực ( Chúng ta khảo sát vài tốn mà đó, thuật tốn tham lam thiết kế dựa mơ hình chia để trị Thuật tốn tham lam cần đưa định tức bước lựa chọn Quyết định ảnh hưởng tới lựa chọn bước Chính vậy, đơi phân tích kỹ hai định liên tiếp cho ta tính chất nghiệm tối ưu từ xây dựng thuật toán hiệu 4.3.4 Lịch xử lý lỗi Bạn người quản trị hệ thống thông tin, hệ thống lúc xảy lỗi đánh số từ tới Lỗi gây thiệt hại sau ngày để khắc phục lỗi cần ngày Tại thời điểm, bạn xử lý lỗi Hãy lên lịch trình xử lý lỗi cho tổng thiệt hại lỗi nhỏ Input Dịng chứa số nguyên dương dòng tiếp theo, dòng chứa hai số nguyên dương Output Lịch xử lý lỗi Sample Input 3 Sample Output Bug 4: fixed time = Bug 2: fixed time = Bug 3: fixed time = Bug 1: fixed time = Minimum Damage = 44 1; 3; 6; 9; damage damage damage damage = = = = 24 2 Do lỗi ngưng gây thiệt hại khắc phục, nên dễ thấy lịch trình cần tìm phải có tính chất: Khi bắt tay vào xử lý lỗi, ta phải làm liên tục lỗi ) tương ứng với thứ tự khắc phục Tức ta cần tìm hốn vị dãy số ( lịch trình khắc phục lỗi ( Giả sử lịch trình ) xử lý lỗi từ tới ( ưu Ta lấy lịch trình khác hai lỗi liên tiếp: ) có cách đảo thứ tự xử lý lịch trình Ta nhận xét ngồi hai lỗi , thời điểm lỗi khác khắc phục giống hai lịch trình, có nghĩa khác biệt tổng thiệt hại lịch trình nằm thiệt hại hai lỗi Gọi thời điểm lỗi ( ) ( ( Nếu theo lịch trình ) gây là: ) (4.5) ), thiệt hại hai lỗi ( Thiệt hại theo lịch trình ) Khi đó: ), thiệt hại hai lỗi ( lịch trình gây khắc phục (trên hai lịch trình Nếu theo lịch trình thiệt hại lịch trình tối ( gây là: ) (4.6) khơng thể lớn thiệt hại theo lịch trình (do tối ưu), tức không lớn thiệt hại Loại bỏ hạng tử giống cơng thức tính , ta có: (4.7) ( Vậy lịch trình Ngồi thấy ) tối ưu, phải thỏa mãn: , hai lịch trình sửa chữa thiệt hại Trong trường hợp này, việc sửa lỗi trước hay có mức độ trước cho phương án tối ưu Từ suy phương án tối ưu cần tìm phương án khắc phục lỗi theo thứ tự tăng dần tỉ số () () Lời giải lặp đơn thuật toán xếp BUGFIXSCHEDULING.PAS Lịch xử lý lỗi {$MODE OBJFPC} program BugFixes; const max = 100000; type TBug = record d, t: Integer; end; var bugs: array[1 max] of TBug; id: array[1 max] of Integer; n: Integer; procedure Enter; //Nhập liệu var i: Integer; begin ReadLn(n); for i := to n with bugs[i] begin ReadLn(d, t); id[i] := i; end; end; ịnh nghĩa i toán tử < lỗi Lỗi x gọi “nhỏ hơn” ỗi y n u x.t/x.d < y.t/y.d operator < (const x, y: TBug): Boolean; begin Result := x.t * y.d < y.t * x.d; end; //Sắp x p lỗi bugs[L H] theo quan hệ thứ tự “nhỏ hơn” định nghĩa procedure QuickSort(L, H: Integer); var i, j: Integer; pivot: Integer; begin if L >= H then Exit; i := L + Random(H - L + 1); pivot := id[i]; id[i] := id[L]; i := L; j := H; repeat while (bugs[pivot] < bugs[id[j]]) and (i < j) Dec(j); if i < j then begin id[i] := id[j]; Inc(i); end else Break; while (bugs[id[i]] < bugs[pivot]) and (i < j) Inc(i); if i < j then begin id[j] := id[i]; Dec(j); end else Break; until i = j; id[i] := pivot; QuickSort(L, i - 1); QuickSort(i + 1, H); end; procedure PrintResult; //In k t var i: Integer; Time, Damage: Integer; TotalDamage: Int64; begin Time := 0; TotalDamage := 0; for i := to n with bugs[id[i]] begin Time := Time + t; Damage := Time * d; WriteLn('Bug ', id[i], ': fixed time = ', Time, '; damage = ', Damage); Inc(TotalDamage, Damage); end; WriteLn('Minimum Damage = ', TotalDamage); end; begin Enter; QuickSort(1, n); PrintResult; end 4.3.5 Thuật toán Johnson Bài toán Bài tốn lập lịch gia cơng hai máy (Two-machine flow shop model): Có từ tới hai máy Một chi tiết cần gia công máy công máy Thời gian gia công chi tiết máy chi tiết đánh số trước chuyển sang gia và Tại thời điểm, máy gia cơng chi tiết Hãy lập lịch gia công chi tiết cho việc gia cơng tồn chi tiết hồn thành thời gian sớm Input Dòng chứa số nguyên dương Dòng chứa số nguyên dương ( ) Dòng chứa số nguyên dương ( ) Output Lịch gia công tối ưu Sample Input 4 Sample Job 2: Job 1: Job 4: Job 3: Time = Output A[0, 1]; B[1, 3] A[1, 4]; B[4, 8] A[4, 8]; B[8, 11] A[8, 10]; B[11, 12] 12 10 11 12 2 4 Thuật tốn Nhận xét ln tồn lịch gia công tối ưu mà chi tiết gia công máy theo thứ tự gia công máy hoạt động liên tục không nghỉ máy theo thứ tự Máy có khoảng thời gian chết chờ chi tiết từ máy Như ta cần tìm lịch gia cơng tối ưu dạng hoán vị dãy số ( ) Định lý 4-6 (Định lý Johnson) Một lịch gia công tối ưu cần thỏa mãn tính chất: Nếu chi tiết gia cơng trước chi tiết ( ) cơng chi tiết ( chi tiết ) Hơn ( ) ( ) việc đảo thứ tự gia phương án tối ưu trì tính tối ưu phương án Định lý 4-7 Xét quan hệ hai “nhỏ bằng” (ký hiệu ) xác định tập chi tiết Quan hệ định nghĩa sau: nếu: Hoặc ( ) ( ) Hoặc ( ) ( ) Khi quan hệ quan hệ thứ tự tồn phần (có đầy đủ tính chất: phổ biến, phản xạ, phản đối xứng, bắc cầu) Việc chứng minh cụ thể hai định lý dài dịng, bạn tham khảo tài liệu khác Cài đặt Định lý 4-6 (Định lý Johnson) Định lý 4-7 thuật tốn Johnson cài đặt thuật toán xếp so sánh Tuy nhiên cài đặt thuật toán xếp so sánh, cần cài đặt phép toán : cho biết chi tiết bắt buộc phải gia công trước chi tiết việt kiểm tra bất đẳng thức ( ( ) ), gia công chi tiết trước hay trước JOHNSONALG.PAS Thuật toán Johnson {$MODE OBJFPC} program JohnsonAlgorithm; uses Math; const maxN = 100000; type TJob = record a, b: Integer; end; var jobs: array[1 maxN] of TJob; id: array[1 maxN] of Integer; ( ) Bởi ( ) n: Integer; procedure Enter; //Nhập liệu var i: Integer; begin ReadLn(n); for i := to n Read(jobs[i].a); ReadLn; for i := to n Read(jobs[i].b); for i := to n id[i] := i; end; ịnh nghĩa toán tử "phải m tr ớc": < Chi ti t x phải m tr ớc chi ti t y n u Min(x.a, y.b) < Min(y.a, x.b) operator < (const x, y: TJob): Boolean; //Toán tử dùng cho x p begin Result := Min(x.a, y.b) < Min(y.a, x.b); end; //Thuật toán QuickSort x p b ng số procedure QuickSort(L, H: Integer); var i, j: Integer; pivot: Integer; begin if L >= H then Exit; i := L + Random(H - L + 1); pivot := id[i]; id[i] := id[L]; i := L; j := H; repeat while (jobs[pivot] < jobs[id[j]]) and (i < j) Dec(j); if i < j then begin id[i] := id[j]; Inc(i); end else Break; while (jobs[id[i]] < jobs[pivot]) and (i < j) Inc(i); if i < j then begin id[j] := id[i]; Dec(j); end; else Break; until i = j; id[i] := pivot; QuickSort(L, i - 1); QuickSort(i + 1, H); end; procedure PrintResult; //In k t var StartA, StartB, FinishA, FinishB: Integer; i, j: Integer; begin StartA := 0; StartB := 0; for i := to n //Duyệt anh sách đ x p begin j := id[i]; FinishA := StartA + jobs[j].a; StartB := Max(StartB, FinishA); FinishB := StartB + jobs[j].b; WriteLn('Job ', j, ': ', 'A[', StartA, ', ', FinishA, ']; B[', StartB, ', ', FinishB, ']'); StartA := FinishA; StartB := FinishB; end; WriteLn('Time = ', FinishB); end; begin Enter; QuickSort(1, n); PrintResult; end Thời gian thực thuật toán Johnson cài đặt theo cách đánh giá thời gian )) Có thể cài đặt thực giải thuật xếp Ở ta dùng QuickSort (Trung bình ( thuật toán Johnson theo cách khác để tận dụng thuật tốn xếp dãy khóa số, cách làm sau: Chia chi tiết làm hai nhóm: Nhóm chi tiết có gồm chi tiết có Sắp xếp chi tiết nhóm xếp chi tiết nhóm nhóm gồm theo thứ tự tăng dần theo thứ tự giảm dần , nối hai danh sách xếp lại Bài tập 4-1 Bạn người lập lịch giảng dạy cho điểm chuyên đề, chuyên đề thứ cần bắt đầu sau thời ] Mỗi chuyên đề thời gian diễn gia hoạt động kết thúc thời điểm : ( giảng dạy cần phòng học riêng Hãy xếp lịch giảng dạy cho số phịng học phải sử ) dụng Tìm thuật toán ( Bài tập 4-2 Trên trục số cho điểm đen điểm trắng hoàn toàn phân biệt Hãy tìm đoạn, đoạn nối điểm đen với điểm trắng, cho khơng có hai đoạn thẳng có chung đầu ) mút tổng độ dài đoạn nhỏ Tìm thuật tốn ( Bài tập 4-3 Xét mã phi tiền tố tập ký tự Nếu ký tự xếp sẵn theo thứ tự khơng giảm tuần suất xây dựng Huffman thời gian ( ) cách sử dụng hai hàng đợi: Tạo nút chứa ký tự đẩy chúng vào hàng đợi theo thứ tự từ nút tần suất thấp tới nút tần suất cao Khởi tạo hàng đợi rỗng, lặp lại thao tác sau lần: Lấy hai nút có tần suất thấp khỏi hàng đợi cách đánh giá phần tử đầu hai hàng đợi Tạo nút làm nút cha hai nút với tần suất tổng tần suất Đẩy vào cuối hàng đợi Chứng minh tính đắn cài đặt thuật toán Bài tập 4-4 Bài tốn xếp ba lơ (Knapsack) khảo sát chuyên đề kỹ thuật nhánh cận quy hoạch động toán 0/1 Knapsack: Với sản phẩm có hai trạng thái: chọn hay khơng chọn Chúng ta khảo sát toán Fractional Knapsack: Cho phép chọn phần sản phẩm: Với sản phẩm trọng lượng lượng giá trị , ta lấy phần trọng sản phẩm giá trị Chỉ hàm mục 1.4.3 cho kết tối ưu toán Fractional Knapsack Bài tập 4-5 Giáo sư lái xe chuyến hành trình “ uyên Việt” từ Cao Bằng tới Cà Mau dài km Dọc đường có trạm xăng trạm xăng thứ cách Cao Bằng đổ đầy km Bình xăng xe km Hãy xác định điểm dừng để đổ xăng trạm xăng cho số lần phải dừng đổ xăng hành trình Bài tập 4-6 Cho Hãy đoạn dạng [ điểm thực trục số: số nguyên để phủ hết ] với điểm cho Bài tập 4-7 Bạn có nhiệm vụ, nhiệm vụ cần làm đơn vị thời gian Nhiệm vụ thứ có thời điểm phải hồn thành (deadline) phải khoản phạt bạn hồn thành nhiệm vụ sau thời hạn Bạn thời điểm thời điểm thực nhiệm vụ Hãy lên lịch thực nhiệm vụ cho tổng số tiền bị phạt Bài tập 4-8 Một lần Tôn Tẫn đua ngựa với vua Tề Tơn Tẫn vua Tề người có từ tới , ngựa thứ Tơn Tẫn có tốc độ ngựa đánh số , ngựa thứ vua Tề có tốc độ Luật chơi sau: Có tất cặp đua, cặp đua có ngựa Tơn Tẫn ngựa vua Tề Con ngựa phải tham gia cặp đua Trong cặp đua, ngựa tốc độ cao thắng, hai ngựa có tốc độ kết cặp đua hồ Trong cặp đua, ngựa bên thắng bên điểm, hồ thua khơng có điểm Hãy giúp Tôn Tẫn chọn ngựa đấu - Điểm vua Tề lớn cặp đua với vua Tề cho hiệu số: Điểm Tôn Tẫn Tài liệu tham khảo Adelson-Velsky, Georgy Maximovich and Landis, Yevgeniy Mikhailovich An algorithm for the organization of information In Proceedings of the USSR Academy of Sciences ( 1962), 263-266 Aho, Alfred V., Hopcroft, John E., and Ullman, Jeffrey D Data Structures and Algorithms Addison Wesley, 1983 Barahona, Francisco and Tardos, Éva Note on Weintraub's Minimum-Cost Circulation Algorithm SIAM Journal on Computing, 18, (1989), 579-583 Bayer, Rudolf Symmetric binary B-Trees: Data structure and maintenance algorithms Acta Informatica, (1972), 290–306 Bellman, Richard On a Routing Problem Quarterly of Applied Mathematics, 16, (1958), 87-90 Bentley, J.L Solution to Klee's rectangle problems Carnegie-Mellon university, Pittsburgh, PA, 1977 Coppersmith, Don and Winograd, Shmuel Matrix multiplication via arithmetic progressions In STOC '87: Proceedings of the nineteenth annual ACM symposium on Theory of computing (New York, United States 1987), ACM, 1-6 Cormen, Thomas H., Leiserson, Charles Eric, Rivest, Ronald Linn, and Stein, Clifford Introduction to Algorithms MIT Press, 2009 de Berg, Mark, Cheong, Otfried, van Kreveld, Marc, and Overmars, Mark Computational Geometry: Algorithms and Applications Springer-Verlag, 2008 10 Dijkstra, Edsger Wybe A note on two problems in connexion with graphs Numerische Mathematik, (1959), 269-271 11 Ding, Yuzheng and Weiss, Mark A Best case lower bounds for heapsort Computing, 49, (1993), 1-9 12 Dinic, E A Algorithm for solution of a problem of maximum flow in networks with power estimation Soviet Mathematics Doklady, 11, (1970), 1277-1280 13 Edmonds, Jack and Karp, Richard Manning Theoretical improvements in the algorithmic efficiency for network flow problems Journal of the ACM, 19 (1972), 248-264 14 Fenwick, Peter M A New Data Structure for Cumulative Frequency Tables Software: Practice and Experience, 24 (1994), 327-336 15 Fische, Johannes and Heun, Volker A New Succinct Representation of RMQ-Information and Improvements in the Enhanced Suffix Array Lecture Notes in Computer Science, 4614 (2007), 459-470 16 Floyd, Robert W Algorithm 245 - Treesort Communications of the ACM, 7, 12 (1964), 701 17 Ford, Lester Randolph and Fulkerson, Delbert Ray Flows in Networks Princeton University Press, 1962 18 Ford, Lester Randolph and Johnson, Selmer M A Tournament Problem The American Mathematical Monthly, 66, (1959), 387-389 19 Fredman, Michael Lawrence and Tarjan, Robert Endre Fibonacci heaps and their uses in improved network optimization algorithms Journal of the ACM, 34, (1987), 596-615 20 Goldberg, Andrew Vladislav Efficient graph algorithms for sequential and parallel computers MIT, 1987 21 Goldberg, Andrew Vladislav and Robert, Endre Tarjan Finding minimum-cost circulations by canceling negative cycles Journal of the ACM (JACM), 36, (1989), 873886 22 Hoare, Charles Antony Richard QuickSort Computer Journal, 5, (1962), 10-15 23 Hopcroft, John Edward and Karp, Richard Manning An n^(5/2) algorithm for maximum matchings in bipartite graphs SIAM Journal on Computing, 2, (1973), 225-231 24 Hopcroft, John Edward and Tarjan, Robert Endre Efficient algorithms for graph manipulation Communications of the ACM, 16, (1973), 372-378 25 Huffman, David Albert A Method for the Construction of Minimum-Redundancy Codes Proceedings of the Institute of Radio Engineers, 40, (1952), 1098-1101 26 Karatsuba, Anatolii Alexeevich and Ofman, Yu Multiplication of Many-Digital Numbers by Automatic Computers Doklady Akad Nauk SSSR, 145 (1962), 293-294 Translation in Physics-Doklady 7, 595-596, 1963 27 Karp, Manning Richard A characterization of the minimum cycle mean in a digraph Discrete Mathematics , 23, (1978), 309-311 28 Klein, Morton A Primal Method for Minimal Cost Flows with Applications to the Assignment and Transportation Problems Management Science, 14, (1967), 205-220 29 Kruskal, Joseph Bernard On the Shortest Spanning Subtree of a Graph and the Traveling Salesman Problem Proceedings of the American Mathematical Society, 7, (1956), 48-50 30 Kuhn, Harold The Hungarian Method for the assignment problem 31 Lacey, Stephen and Box, Richard A fast, easy sort BYTE, 16, (1991), 315-ff 32 Musser, David R Introspective Sorting and Selection Algorithms Software: Practice and Experience, 27, (1997), 983 - 993 33 Nguyễn, Đức Nghĩa and Nguyễn, Tơ Thành Tốn Rời R c NXB Giáo Dục, 1999 34 Prim, Robert Clay Shortest connection networks and some generalizations Bell System Technical Journal, 36 (1957), 1389-1401 35 Seidel, Raimund G and Aragon, Cecilia R Randomized search trees Algorithmica, 16 (1996), 464-497 36 Shell, Donald L A high-speed sorting procedure Communications of the ACM, 2, (1959), 30-32 37 Sleator, Daniel Dominic and Tarjan, Robert Endre Self-Adjusting Binary Search Trees Journal of the ACM, 32, (1985), 652-686 38 Sokkalingam, P T., Ahuja, Ravindra K., and Orlin, James B New Polynomial-Time CycleCanceling Algorithms for Minimum Cost Flows Network, 36 (1996), 53-63 39 Stoer, Mechthild and Wagner, Frank A simple min-cut algorithm Journal of the ACM (JACM), 44, (1997), 585-591 40 Strassen, Volker Gaussian Elimination is not Optimal Numerische Mathematik, 13, (1969), 354-356 41 Tarjan, Robert Endre Depth first search and linear graph algorithms SIAM Journal on Computing, 1, (1972), 146-160 42 Vuillemin, Jean A data structure for manipulating priority queues Communications of the ACM, 21, (1978), 309-314 43 Williams, J.W.J Algorithm 232: Heapsort Communications of the ACM, 7, (1964), 347348 ... lenP, lenQ, len: Integer; begin lenP := Length(p); lenQ := Length(q); len := Max(lenP, lenQ); SetLength(p, len); SetLength(q, len); if lenP < len then //p bị tăng bậc FillChar(p[lenP], (len -. .. FillChar(p[lenP], (len - lenP) * SizeOf(Real), 0); if lenQ < Length(q) then //q bị tăng bậc FillChar(q[lenQ], (len - lenQ) * SizeOf(Real), 0); end; t p[lenP len - 1] := t q[lenQ len – 1] := 0; procedure... giải toán Knapsack cho đời nhiều thuật toán gần đúng, thuật toán tối ưu trường hợp đặt biệt (chẳng hạn thuật toán quy hoạch động số nguyên tương đối nhỏ) Dưới ta xây dựng thuật toán quay lui kỹ thuật