1. Trang chủ
  2. » Giáo án - Bài giảng

Sap xep va tim kiem

18 519 4
Tài liệu đã được kiểm tra trùng lặp

Đ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

Thông tin cơ bản

Định dạng
Số trang 18
Dung lượng 350 KB

Nội dung

CÁC THUẬT TOÁN SẮP XẾP 1. Giới thiệu bài toán Ta sẽ xem xét các thuật toán để sắp xếp một tập các bản ghi theo giá trị của một trường nào đó. Thứ tự sắp xếp là một quy luật đã được định nghĩa rõ ràng: thường là thứ tự tăng dần (hay giảm dần) đối với dãy số, thứ tự từ điển đối với các chữ, . Bài toán đặt ra ở đây là sắp xếp đối với một tập gồm n bản ghi r 1 , r 2 , ., r n . Tuy nhiên không phải toàn bộ các trường dữ liệu trong bản ghi đều được xét đến trong quá trình sắp xếp mà chỉ một hoặc vài trường nào đó thôi. Trường như vậy gọi là trường khoá. Sắp xếp sẽ được tiến hành dựa vào giá trị của khoá này. Do khoá có vai trò đặc biệt như vậy nên sau này khi trình bày các thuật toán hay trong các ví dụ minh hoạ, ta sẽ coi nó như đại diện cho bản ghi để đơn giản hơn ta chỉ nói đến khoá thôi. Thực ra phép đổi chỗ được tác động lên các bản ghi ở đây ta cũng chỉ nói đến phép đổi chỗ với các khoá. Giá trị khoá có thể là số hay chữ thứ tự sắp xếp cũng được quy định tương ứng với khoá. Ở đây để minh hoạ cho các thuật toán sắp xếp ta sẽ coi giá trị khoá là số thứ tự sắp xếp là tăng dần. Bây giờ bài toán sắp xếp được đặt ra đơn giản nhưng vẫn không làm mất tính tổng quát như sau: cho một dãy các khoá a 1 , a 2 , ., a n là các số nguyên (tương ứng với các bản ghi r 1 , r 2 , ., r n ). Hãy sắp xếp các khoá trên theo thứ tự tăng dần. 2. Các thuật toán sắp xếp đơn giản a. Sắp xếp kiểu lựa chọn (Selection sort) Một trong những phương pháp đơn giản nhất để sắp xếp là dựa trên phép lựa chọn: đầu tiên tìm phần tử nhỏ nhất trong dãy hoán vị nó với phần tử trong vị trí đầu tiên. Sau đó tìm phần tử nhỏ nhất kế tiếp hoán vị nó với phần tử trong vị trí thứ hai tiếp tục theo phương pháp này cho đến khi toàn bộ dãy được sắp xếp. Cách sắp xếp mà ta vẫn thường sử dụng trước đây chính là phương pháp này. Để tìm phần tử nhỏ nhất thứ i (i = 1, 2, ., n-1) ta so sánh nó với các phần tử thứ j đứng sau nó (j = i+1, ., n), vì các phần tử đứng trước đã được đứng đúng vị trí. Nếu phần tử thứ j nào nhỏ hơn phần tử thứ i thì ta đổi chỗ 2 phần tử này với nhau. Như vậy phần tử thứ i luôn giữ lại phần tử nhỏ nhất, vì vậy sau một lượt duyệt đối với j thì phần tử nhỏ nhất thứ i sẽ nằm ở vị trí thứ i. Thủ tục sắp xếp kiểu lựa chọn được cài đặt như sau: procedure selection; var i, j, t : integer; begin for i := 1 to n do for j := i+1 to n do if a[i] > a[j] then begin t := a[i]; a[i] := a[j]; a[j] := t; end; end; b. Sắp xếp kiểu thêm dần (Insertion sort) Nguyên tắc sắp xếp ở đây dựa theo kinh nghiệm của những người chơi bài. Khi có i-1 lá bài đã được sắp xếp ở trên tay, nay rút thêm lá bài thứ i nữa thì sắp xếp lại như thế nào? Có thể so sánh lá bài mới rút lần lượt với các lá bài đã có ở trên tay để tìm ra “chỗ” thích hợp “chèn” nó vào chỗ đó. 1 Dựa vào nguyên tắc trên ta có thể xây dựng thuật toán sắp xếp như sau: lúc đầu dãy coi như chỉ có một khoá là a 1 đã được sắp xếp. Xét thêm a 2 , so sánh nó với a 1 để xác định chỗ chèn nó vào, sau đó ta có một dãy gồm hai khoá đã được sắp xếp. Cứ tiếp tục như vậy đối với a 3 , a 4 , . Cuối cùng sau khi xét xong a n thì dãy khoá đã được sắp xếp hoàn toàn. Hình ảnh của thuật toán sắp xếp kiểu thêm dần với dãy khóa 42, 23, 74, 11, 65, 58 được minh hoạ qua bảng sau: Lượt 1 2 3 4 5 6 Khoá đưa vào 42 23 74 11 65 58 1 42 23 23 11 11 11 2 42 42 23 23 23 3 74 42 42 42 4 74 65 58 5 74 65 6 74 Thủ tục sắp xếp kiểu thêm dần được cài đặt như sau: procedure insertion; var i, j, t : integer; begin for i := 2 to n do begin t := a[i]; j := i - 1; while (j >= 1) and (a[j] > t) do begin a[j+1] := a[j]; j := j - 1; end; a[j+1] := t; end; end; c. Sắp xếp nổi bọt (Bubble sort) Ý tưởng của thuật toán này như sau: dãy các khoá sẽ được duyệt từ đáy lên đỉnh. Dọc đường nếu gặp hai khoá kế cận ngược thứ tự thì đổi chỗ chúng cho nhau. Như vậy trong lượt đầu tiên khoá có giá trị nhỏ nhất sẽ chuyển dần lên đỉnh. Đến lượt thứ hai, khoá có giá trị nhỏ thứ hai sẽ được chuyển đến vị trí thứ hai, . Nếu hình dung khoá được đặt thẳng đứng thì sau từng lượt sắp xếp các giá trị khoá nhỏ sẽ “nổi” dần lên giống như các bọt nước nổi lên trong nồi nước đang sôi. Vì vậy thuật toán này được gọi với tên khá đặc trưng là sắp xếp kiểu nổi bọt. Quá trình sắp xếp của thuật toán nổi bọt có thể minh hoạ qua bảng sau: i a i Lượt 1 2 3 4 5 1 42 11 11 11 11 11 2 23 42 23 23 23 23 3 74 23 42 42 42 42 4 11 74 58 58 58 58 5 65 58 74 65 65 65 2 6 58 65 65 74 74 74 Thủ tục sắp xếp nổi bọt được cài đặt như sau: procedure bubble; var i, j, t : integer; begin for i := 1 to n-1 do for j := n downto i+1 do if a[j] < a[j-1] then begin t := a[j]; a[j] := a[j-1]; a[j-1] := t; end; end; d. Phân tích tính hiệu quả của các thuật toán sắp xếp đơn giản Cả ba thuật toán đều có độ phức tạp thời gian cỡ O(n 2 ) độ phức tạp bộ nhớ là O(n). Vì vậy, ta sẽ lấy thuật toán sắp xếp kiểu lựa chọn đại diện cho các thuật toán sắp xếp đơn giản để thực hiện với các bộ test sau trên máy tính PentiumIV 3.0Ghz. Để thuật tiện cho quá trình test với dữ liệu lớn, ta có chút thay đổi một chút khi cài đặt là thay tất cả các biến kiểu interger thành các biến kiểu longint. Sau đây là bảng kết quả khi thực hiện thuật toán: TT n Mô tả Thời gian (giây) 1 10 Kích thước nhỏ (tạo bằng tay) 0.00 2 100 Kích thước nhỏ (tạo ngẫu nhiên) 0.00 3 1.000 Kích thước nhỏ (tạo ngẫu nhiên) 0.00 4 10.000 Kích thước trung bình (tạo ngẫu nhiên) 0.61 5 15.000 Kích thước trung bình (tạo ngẫu nhiên) 1.32 6 50.000 Kích thước trung bình (tạo ngẫu nhiên) 14.21 7 100.000 Kích thước lớn (tạo có chủ định: nửa đầu giảm, nửa sau tăng) 57.97 8 500.000 Kích thước lớn (tạo ngẫu nhiên) 1426.07 9 1.000.000 Kích thước lớn (tạo ngẫu nhiên) Quá lâu 10 1.000.000 Kích thước lớn (tạo có chủ định: nửa đầu tăng, nửa sau giảm) Quá lâu Nhìn vào bảng kết quả trên, ta thấy rằng các thuật toán cơ bản chỉ áp dụng với n ≤ 10.000. Tuy nhiên với n lớn thì chi phí về thời gian thực hiện của cả ba thuật toán trên là một chi phí cao so với một số thuật toán mà ta sẽ xét sau đây. 3. Thuật toán sắp xếp nhanh (Quick sort) Sắp xếp nhanh Quick sort là thuật toán được A.R. Hoare phát minh vào năm 1960. Quick sort là phương pháp sắp xếp phổ biến vì việc cài đặt nó không khó khăn. Ý tưởng của thuật toán như sau: chọn một khoá ngẫu nhiên nào đó làm “chốt”, thường là phần tử nằm giữa dãy. Mọi phần tử nhỏ hơn “khoá chốt” phải được xếp vào vị trí ở trước “chốt” (đầu dãy), mọi phần tử lớn hơn khoá “chốt” phải được xếp sau “chốt” (cuối dãy). Muốn vậy các phần tử trong dãy phải được so sánh với khoá chốt sẽ đổi vị trí cho nhau, nếu nó lớn hơn chốt mà lại nằm trước chốt hoặc nhỏ hơn chốt mà lại nằm sau chốt. 3 Khi thực hiện việc đổi chỗ xong thì dãy khoá được chia làm hai đoạn: một đoạn gồm các khoá nhỏ hơn chốt, một đoạn gồm các khoá lớn hơn hoặc bằng chốt. ở các bước tiếp theo ta cũng áp dụng kỹ thuật trên cho các phân đoạn. Quá trình xử lý một phân đoạn dừng lại khi ta gặp một phân đoạn chỉ gồm một phần tử. Việc sắp xếp sẽ kết thúc khi phân đoạn cuối cùng đã được xử lý xong. Thuật toán Quick sort được mô tả như sau: Bước 1: • Chọn khoá đứng giữa dãy làm khoá chốt x := a[(l+r) div 2]; (l, r là 2 biến chỉ số đầu, cuối của một phân đoạn) • Dùng 2 biến chỉ số i, j để phát hiện ra hai khoá cần đổi chỗ. Khởi tạo giá trị ban đầu cho hai biến này: i := l; j := r; Bước 2: • Duyệt từ trái sang phải để tìm chỉ số i sao cho a[i] >= x. • Duyệt từ phải sang trái để tìm chỉ số j sao cho a[j] <= x. • Nếu i <= j thì: Đổi chỗ a[i] a[j]. i := i + 1. j := j - 1. Lặp lại bước 2 cho đến khi i > j. Bước 3: • Nếu l < j thì lặp lại bước 1, 2 cho phân đoạn a[l], ., a[j]. • Nếu i < r thì lặp lại bước 1, 2 cho phân đoạn a[i], ., a[r]. Hình ảnh sau đây minh họa diễn biến trong lượt đầu của thuật toán với dãy số: 42, 23, 65, 74, 11, 58. Khóa chốt x = 65. i↓ j↓ 42 23 65 74 11 58 ↑_____________↑ i↓ j↓ 42 23 58 74 11 65 ↑___↑ j↓ i↓ 42 23 58 11 74 65 Dãy khoá được chia làm hai phân đoạn: (42, 23, 58 11) (74, 65). Công việc tiếp theo lại tiến hành lần lượt trên hai phân đoạn mới này. Cài đặt: procedure qSort(l, r : integer); var i, j, x, y : integer; begin i := l; j := r; x := a[(l+r) div 2]; repeat while a[i] < x do i := i + 1; while x < a[j] do j := j – 1; if i <= j then begin 4 y := a[i]; a[i] := a[j]; a[j] := y; i := i + 1; j := j – 1; end; until i > j; if l < j then qSort(l, j); if i < r then qSort(i, r); end; Khi đó trong thân của chương trình chính ta chỉ gọi qSort(1, n); Bây giờ ta sẽ đánh giá độ phức tạp thời gian của thuật toán Quick sort. Trường hợp tốt nhất của Quick sort xảy ra khi dãy khoá luôn được chia đôi thì độ phức tạp tính toán của thuật toán là O(n.log 2 n). Như vậy khi n khá lớn thì Quick sort tỏ ra hiệu lực hơn các thuật toán đơn giản mà ta đã xét. Trường hợp xấu nhất của Quick sort xảy ra khi nửa đầu của dãy khoá đã có thứ tự sắp xếp nửa dãy còn lại có thứ tự ngược lại hoặc nửa đầu có thứ tự ngược với thứ tự cần sắp xếp nửa sau đã được sắp xếp thì độ phức tạp của thuật toán là O(n 2 ). Trường hợp này Quick sort không hơn gì các thuật toán đơn giản đã nêu. Một trong những yếu điểm của Quick sort là tính đệ quy. Sau đây là kết quả thực hiện thuật toán Quick sort với các bộ dữ liệu đã dùng cho các thuật toán sắp xếp đơn giản để tiện theo dõi so sánh: TT n Mô tả Thời gian (giây) Đơn giản Phân đoạn 1 10 Kích thước nhỏ (tạo bằng tay) 0.00 0.00 2 100 Kích thước nhỏ (tạo ngẫu nhiên) 0.00 0.00 3 1.000 Kích thước nhỏ (tạo ngẫu nhiên) 0.00 0.00 4 10.000 Kích thước trung bình (tạo ngẫu nhiên) 0.61 0.01 5 15.000 Kích thước trung bình (tạo ngẫu nhiên) 1.32 0.02 6 50.000 Kích thước trung bình (tạo ngẫu nhiên) 14.21 0.05 7 100.000 Kích thước lớn (tạo có chủ định: nửa đầu giảm, nửa sau tăng – trường hợp xấu của Quick sort) 27.42 6.25 8 500.000 Kích thước lớn (tạo ngẫu nhiên) 1426.07 0.57 9 1.000.000 Kích thước lớn (tạo ngẫu nhiên) Quá lâu 1.11 10 1.000.000 Kích thước lớn (tạo có chủ định: nửa đầu tăng, nửa sau giảm – trường hợp xấu của Quick sort) Quá lâu Quá lâu 4. Thuật toán sắp xếp kiểu vun đống (Heap sort) Sắp xếp kiểu vun đống được chia làm 2 giai đoạn: • Giai đoạn đầu người ta coi dãy khoá cần sắp như là cấu trúc của một cây nhị phân hoàn chỉnh: nếu i chỉ vị trí nút con thì (i div 2) chỉ vị trí nút cha, còn nếu j chỉ vị trí nút cha thì 2.j 2.j + 1 chỉ nút con. Sau đó cây nhị phân biểu diễn dãy khoá này được biến đổi để trở thành một đống. ở đây đống là một cây nhị phân hoàn chỉnh mà mỗi nút được gán cho một giá trị khoá sao cho khoá của nút cha bao giờ cũng lớn hơn khoá của nút con nó. Do đó khoá của nút gốc của đống chính là khoá lớn nhất (khoá trội) so với mọi khoá trên cây. Giai đoạn này gọi là giai đoạn tạo đống. • Giai đoạn thứ hai là sắp xếp. Ta thực hiện lặp các việc sau cho đến khi dãy khoá được sắp:  Đưa khoá trội về vị trí thực của nó bằng cách đổi chỗ với khoá hiện đang ở vị trí đó.  Sau đó “vun lại thành đống” đối với các khoá còn lại (sau khi đã loại khoá trội ra ngoài). 5 Điểm mấu chốt của thuật toán là việc tạo đống hay vun đống. Mặt khác ta nhận thấy rằng một nút lá có thể coi là một cây con đã thoả mãn tính chất của đống rồi. Như vậy việc tạo đống hay vun đống có thể được tiến hành theo kiểu từ đáy lên (bottom-up). Khi đó bài toán này sẽ được quy về một phép xử lý chung sau đây: chuyển đổi thành đống cho một cây mà cây con trái cây con phải đã là đống rồi. Thủ tục adjust(i, n : integer) sau đây sẽ chỉnh sửa một cây nhị phân với gốc i để nó thành đống. Giả sử cây con trái cây con phải của i, tức là cây với gốc 2.i 2.i + 1 đã thỏa mãn điều kiện của đống. Không có nút nào ứng với chỉ số lớn hơn n cả. procedure adjust(i, n : integer); var t : integer; begin repeat i := i * 2; if i > n then break; if (i < n) and (a[i] < a[i+1]) then i := i + 1; { tìm nút con lớn hơn } if a[i div 2] >= a[i] then break; t := a[i div 2]; a[i div 2] := a[i]; a[i] := t; until false; end; Khi đó thuật toán sắp xếp kiểu vun đống được cài đặt như sau: procedure heapSort; var i, t : integer; begin { 1. Tạo đống } for i := (n div 2) downto 1 do adjust(i, n); { 2. Sắp xếp } for i := n downto 2 do begin { đưa khoá trội về vị trí thực của nó } t := a[1]; a[1] := a[i]; a[i] := t; { vun các khoá còn lại thành đống } adjust(1, i-1); end; end; Ví dụ sau đây minh họa các bước của thuật toán vun đống với dãy khoá 42, 23, 74, 11, 65, 58. Bước 1. Tạo đống 6 i = 3 42 23 11 65 74 58 42 23 11 65 74 58 i = 1 74 65 11 23 58 42 42 65 11 23 74 58 i = 2 Bước 2. Sắp xếp Đối với thuật toán sắp xếp kiểu vun đống, người ta đã chứng minh được trong tất cả các trường hợp chi phí về thời gian đều là O(n.log 2 n). Đây là một chi phí tốt hơn so với các phương pháp sắp xếp đơn giản. Dưới đây là bảng thực hiện thuật toán sắp xếp kiểu vun đống: TT n Mô tả Thời gian (giây) Đơn giản Phân đoạn Vun đống 1 6 Kích thước nhỏ (tạo bằng tay) 0.00 0.00 0.00 2 100 Kích thước nhỏ (tạo ngẫu nhiên) 0.00 0.00 0.00 3 1.000 Kích thước nhỏ (tạo ngẫu nhiên) 0.00 0.00 0.00 4 10.000 Kích thước trung bình (tạo ngẫu nhiên) 0.61 0.01 0.00 5 15.000 Kích thước trung bình (tạo ngẫu nhiên) 1.32 0.02 0.02 6 50.000 Kích thước trung bình (tạo ngẫu nhiên) 14.21 0.05 0.07 7 100.000 Kích thước lớn (tạo có chủ định: nửa đầu giảm, nửa sau tăng – trường hợp xấu của Quick sort) 27.42 6.25 0.11 8 500.000 Kích thước lớn (tạo ngẫu nhiên) 1426.07 0.57 0.70 9 1.000.000 Kích thước lớn (tạo ngẫu nhiên) Quá lâu 1.11 1.45 10 1.000.000 Kích thước lớn (tạo có chủ định: nửa đầu tăng, nửa sau giảm – trường hợp xấu của Quick sort) Quá lâu Quá lâu 1.09 7 65 42 11 23 58 74 i = 6 58 42 11 65 23 74 i = 5 42 11 58 65 23 74 i = 4 23 11 58 65 42 74 i = 3 11 23 58 65 42 74 i = 2 5. Kết luận Qua những thuật toán nêu trên ta thấy rõ cùng một mục đích sắp xếp như nhau mà có nhiều phương pháp kỹ thuật giải quyết khác nhau. Cấu trúc dữ liệu được chọn để hình dung đối tượng của sắp xếp đã ảnh hưởng tới các thuật toán xử lý. Các thuật toán sắp xếp đơn giản đã thể hiện kỹ thuật cơ sở của sắp xếp (dựa vào phép so sánh giá trị khoá) có thời gian thực hiện cỡ O(n 2 ). Vì vậy các phương pháp sắp xếp đơn giản chỉ áp dụng khi n nhỏ (n ≤ 10.000) . Các thuật toán cải tiến như Quick sort, Heap sort đã đạt được khoảng thời gian thực hiện nhỏ hơn, cỡ O(n.log 2 n) nên thường được sử dụng khi n lớn (n > 10.000). Thông thường, nếu các dãy khóa có thứ tự ngẫu nhiên thì người ta dùng thuật toán Quick sort, vì việc cài đặt nó đơn giản. Trong trường hợp dãy khóa vốn có thứ tự sắp xếp hoặc có thứ tự ngược lại với thứ tự sắp xếp thì Quick sort lại không tốt hơn các thuật toán sắp xếp đơn giản, vì vậy trong tình huống này người ta lại dùng Heap sort. Việc khẳng định một phương pháp nào trong các kỹ thuật sắp xếp nói trên luôn luôn tốt hơn mọi kỹ thuật khác là không nên. Việc chọn một thuật toán sắp xếp thích hợp thường tuỳ thuộc vào từng yêu cầu, từng điều kiện cụ thể. Bài tập cho thuật toán Bài 1. Stamps Mọi người đều ghét Raymond. Anh ta là nhà sưu tầm tem lớn nhất trên thế giới vì lẽ đó anh ta thường chế diễu tất cả các nhà sưu tầm tem khác. May thay, mọi người đều yêu Lucy cô ta có một kế hoạch. Cô ấy bí mật hỏi bạn bè cho cô ấy mượn tem, để cô ấy có thể làm cho Raymond xấu hổ bằng cách chứng tỏ bộ sưu tầm tem của mình còn lớn hơn bộ sưu tầm tem của anh ta. Raymond rất tin tưởng vào sự tốt nhất của bộ tem của mình, cho nên anh ta luôn nói cho mọi người biết anh ta sẽ trưng bày bao nhiêu con tem. Lucy biết mình có bao nhiêu con tem cô ta biết rằng mình cần bao nhiêu con tem nữa. Cô ấy cũng biết có bao nhiêu người bạn sẽ cho cô mượn tem mỗi người sẽ cho mượn bao nhiêu. Nhưng cô ấy muốn mượn từ một số người bạn ít nhất có thể. Bạn hãy viết chương trình, tính giúp cô ấy cần mượn tem từ ít nhất bao nhiêu người bạn. Dữ liệu: Dòng đầu tiên của file vào chứa hai số nguyên s n ngăn cách nhau bởi một dấu cách, ở đó s là số con tem tối thiểu mà Lucy cần mượn (1 ≤ s ≤ 1.000.000) n là số người bạn sẽ cho Lucy mượn tem (1 ≤ n ≤ 10.000). Dòng thứ hai chứa n số nguyên là số tem mà mỗi người bạn sẽ cho Lucy mượn (các số nằm trong phạm vi từ 1 đến 10.000). Kết quả: Ghi ra file ra một số duy nhất là số người bạn ít nhất mà Lucy cần mượn tem. Trong trường hợp Lucy không mượn được số tem tối thiểu mình cần thì ghi ra file ra dòng thông báo “impossible”. Ví dụ: stamps.in stamps.out 100 6 13 17 42 9 23 57 3 99 6 13 17 42 9 23 57 2 1000 3 314 159 265 impossible 8 Baif 2. Mixing Milk Vì việc đóng gói sữa là một nghề kinh doanh có lợi nhuận thấp, cho nên việc mua sữa tươi về đóng gói ở mức giá thấp nhất có thể là rất quan trọng. Công ty Merry Milk Makers có một số nông dân chuyên cung cấp sữa mỗi người có một giá bán khác nhau cho công ty. Tuy nhiên vì mỗi con bò chỉ có thể cho một lượng sữa nhất định mỗi ngày nên những người nông dân đó cũng chỉ có một lượng sữa nhất định để bán mỗi ngày. Mỗi ngày, công ty có thể mua một số nguyên lít sữa từ mỗi người nông dân, ít hơn hoặc bằng giới hạn sữa của mỗi người nông dân đó. Cho trước nhu cầu mua sữa mỗi ngày của công ty, giá mỗi lít sữa số lít sữa có sẵn của mỗi người nông dân. Hãy tính số tiền ít nhất mà công ty cần để mua lượng sữa yêu cầu. Giả thiết rằng tổng số sữa của các người nông dân đủ để đáp ứng lượng sữa của công ty. Dữ liệu: Dòng đầu tiên của file vào chứa hai số nguyên N M ngăn cách nhau bởi một dấu cách. N (0 ≤ N ≤ 2.000.000) là số lít sữa mà công ty cần mỗi ngày, M (0 ≤ M ≤ 5000) là số người nông dân cung cấp sữa cho công ty. Dòng thứ i trong số M dòng tiếp theo, chứa hai số nguyên P i A i ngăn cách nhau bởi một dấu cách. P i (0 ≤ P i ≤ 1000) là giá một lít sữa của bác nông dân i, A i (0 ≤ A i ≤ 2.000.000) là số lít sữa tối đa mà bác nông dân có thể bán cho công ty mỗi ngày. Kết quả: File ra gồm một dòng chứa đúng một số nguyên là số tiền nhỏ nhất mà công ty Merry Milk Makers có thể mua sữa mỗi ngày. Ví dụ: milk.in milk.out 100 5 5 20 9 40 3 10 8 80 6 30 630 Bài 3. Directory of telephone numbers Các nhà doanh nghiệp muốn có số điện thoại dễ nhớ. Một cách làm số điện thoại dễ nhớ là có thể đánh vần nó từ một từ hoặc một cụm từ dễ nhớ. Ví dụ, bạn có thể gọi đến trường Đại học Waterloo bằng cách quay cụm từ dễ nhớ TUT-GLOP. Đôi khi chỉ một phần của số điện thoại được sử dụng để đánh vần một từ. Khi bạn quay trở lại khách sạn vào buổi tối, bạn có thể gọi bánh pizza từ quán Gino bằng cách quay số 310-GINO. Một cách khác để làm số điện thoại dễ nhớ là nhóm các chữ số theo một cách dễ nhớ. Bạn có thể gọi bánh pizza từ quầy bán bánh pizza bằng cách gọi số “ba mười” 3-10- 10-10. Dạng chuẩn của số điện thoại là 7 chữ số thập phân có dấu gạch nối giữa chữ số thứ ba thứ tư (ví dụ 888-1200). Bàn phím của điện thoại cung cấp sơ đồ giữa các chữ cái đến các chữ số như sau: A, B C tương ứng với 2 D, E F tương ứng với 3 G, H I tương ứng với 4 9 J, K L tương ứng với 5 M, N O tương ứng với 6 P, R S tương ứng với 7 T, U V tương ứng với 8 W, X Y tương ứng với 9 Không có sơ đồ cho Q Z. Các dấu gạch nối không được quay nó được thêm hoặc bỏ đi khi cần thiết. Dạng chuẩn của TUT-GLOP là 888-4567, dạng chuẩn của 310-GINO là 310-4466 dạng chuẩn của 3-10-10-10 là 310-1010. Hai số điện thoại là giống nhau nếu chúng có cùng một dạng chuẩn (chúng gọi cùng một số). Công ty của bạn cần biên soạn một danh bạ điện thoại của các doanh nghiệp địa phương. Một phần việc quan trọng là bạn muốn kiểm tra xem có hai (hoặc nhiều hơn) các doanh nghiệp có cùng số điện thoại. Dữ liệu: Dòng đầu tiên của file vào chứa số nguyên dương n (n ≤ 10.000) là số điện thoại trong danh bạ. n dòng tiếp theo, mỗi dòng chứa một số điện thoại trong danh bạ. Mỗi số điện thoại là một xâu ký tự gồm các chữ số thập phân, các chữ cái la tinh in hoa (trừ Q Z) dấu gạch nối. Có đúng 7 ký tự trong xâu là các chữ số các chữ cái. Kết quả: Mỗi dòng của file ra chứa thông tin về một số điện thoại xuất hiện nhiều hơn một lần trong bất kỳ dạng nào, bao gồm số điện thoại ở dạng chuẩn, tiếp theo một dấu cách tiếp theo là số lần số diện thoại xuất hiện trong danh bạ. Các dòng của file ra cần sắp xếp theo thứ tự từ điển của số điện thoại. Nếu không có số điện thoại nào trùng nhau thì ghi ra dòng chữ: “No duplicates.” Ví dụ: phone.in phone.out 12 4873279 ITS-EASY 888-4567 3-10-10-10 888-GLOP TUT-GLOP 967-11-11 310-GINO F101010 888-1200 -4-8-7-3-2-7-9- 487-3279 310-1010 2 487-3279 4 888-4567 3 CÁC THUẬT TOÁN TÌM KIẾM 1. Giới thiệu bài toán Việc tìm kiếm là thao tác nền móng cho rất nhiều tác vụ tính toán. Tìm kiếm có nghĩa là tìm một hay nhiều mẩu tin từ một số lượng lớn thông tin đã được lưu trữ. Thông thường thông tin được chia thành các mẩu tin (bản ghi), mỗi mẩu tin có một khoá (key) dùng cho việc tìm kiếm. Mục đích của việc tìm kiếmtìm tất cả các mẩu tin mà khoá của chúng đồng nhất với một khoá đã cho trước. Sau khi một mẩu tin đã tìm thấy, thông tin bên trong nó sẽ cung cấp cho một quá trình xử lý nào đó. 10 [...]... được cài đặt như sau: program dong_goi_san_pham; const FI = 'zxy.in'; FO = 'zxy.out'; var n, k : integer; a : array[1 15000] of integer; m : longint; procedure doc; var i : integer; f : text; begin assign(f, FI); reset(f); readln(f, n, k); for i := 1 to n do readln(f, a[i]); close(f); end; function ok : boolean; var s, t, i : longint; begin s := 1; t := 0; for i := 1 to n do begin if t + a[i] > m then... if t + a[i] > m then begin s := s + 1; t := 0; 13 end; t := t + a[i]; end; ok := (s ai thì tìm kiếm lại được làm với ai+1, , ar Quá trình cứ tiếp tục khi tìm thấy khoá mong muốn hoặc bảng khoá là trở nên rỗng (không tìm thấy) function binarySearch(x : integer) : integer; var l, r, c : integer; begin l := 1; r := n; repeat c := (l+r) div 2; if x < a[c] then r := c-1 else l := c+1; until (a[c] = x) or (l > r); if x = a[c] then binarySearch := c else binarySearch := n+1;... M0 không thỏa mãn thì tất cả các giá trị M < M0 cũng đều không thỏa mãn Vì vậy, để tìm giá trị nhỏ nhất của M ta áp dụng chiến lược tìm kiếm nhị phân Thuật toán 2 được cài đặt như sau: procedure xu_ly; var l, r, i : longint; begin l := 0; r := 0; for i := 1 to n do begin if l < a[i] then l := a[i]; r := r + a[i]; end; repeat m := (l+r) div 2; if ok then r := m else l := m + 1; until l = r; m := l; end; . 'zxy.in'; FO = 'zxy.out'; var n, k : integer; a : array[1 15000] of integer; m : longint; procedure doc; var i : integer; f : text; begin assign(f,. i. Thủ tục sắp xếp kiểu lựa chọn được cài đặt như sau: procedure selection; var i, j, t : integer; begin for i := 1 to n do for j := i+1 to n do if a[i]

Ngày đăng: 21/08/2013, 07:10

HÌNH ẢNH LIÊN QUAN

Hình ảnh của thuật toán sắp xếp kiểu thêm dần với dãy khóa 42, 23, 74, 11, 65, 58 được minh hoạ qua bảng sau: - Sap xep va tim kiem
nh ảnh của thuật toán sắp xếp kiểu thêm dần với dãy khóa 42, 23, 74, 11, 65, 58 được minh hoạ qua bảng sau: (Trang 2)
Quá trình sắp xếp của thuật toán nổi bọt có thể minh hoạ qua bảng sau: - Sap xep va tim kiem
u á trình sắp xếp của thuật toán nổi bọt có thể minh hoạ qua bảng sau: (Trang 2)
Nhìn vào bảng kết quả trên, ta thấy rằng các thuật toán cơ bản chỉ áp dụng với n≤ 10.000 - Sap xep va tim kiem
h ìn vào bảng kết quả trên, ta thấy rằng các thuật toán cơ bản chỉ áp dụng với n≤ 10.000 (Trang 3)
Hình ảnh sau đây minh họa diễn biến trong lượt đầu của thuật toán với dãy số: 42, 23, 65, 74, 11, 58 - Sap xep va tim kiem
nh ảnh sau đây minh họa diễn biến trong lượt đầu của thuật toán với dãy số: 42, 23, 65, 74, 11, 58 (Trang 4)
Dưới đây là bảng thực hiện thuật toán sắp xếp kiểu vun đống: - Sap xep va tim kiem
i đây là bảng thực hiện thuật toán sắp xếp kiểu vun đống: (Trang 7)
Đây là một bài toán trong một kỳ thi, giới hạn thời gian cho phép là 1 giây. Nhìn vào bảng kết quả trên, ta thấy thuật toán 1 chỉ đáp ứng được 4/10 test - Sap xep va tim kiem
y là một bài toán trong một kỳ thi, giới hạn thời gian cho phép là 1 giây. Nhìn vào bảng kết quả trên, ta thấy thuật toán 1 chỉ đáp ứng được 4/10 test (Trang 14)
Các hạt được xem là đầu tiên và thứ hai trong ví dụ trên được đánh dấu trong hình vẽ. - Sap xep va tim kiem
c hạt được xem là đầu tiên và thứ hai trong ví dụ trên được đánh dấu trong hình vẽ (Trang 16)

TỪ KHÓA LIÊN QUAN

TÀI LIỆU CÙNG NGƯỜI DÙNG

TÀI LIỆU LIÊN QUAN

w