Nội dung thuật toán tìm kiếm nhị phân đã được trình bày ở Sách giáo khoa Tin học 10, phần thuật toán và Sách giáo khoa tin học 11 khi giảng dạy về Pascal. Tuy nhiên nếu chỉ nắm bắt được những nội dung này thì học sinh chỉ áp dụng được một bài toán đơn giản là tìm số nguyên k trong 1 dãy số đã sắp xếp. Hiện nay thì tài liệu tham khảo để hướng dẫn việc áp dụng thuật toán tìm kiếm nhị phân cũng rất ít. Trong quá trình tham gia các diễn đàn, giải bài tập, đề thi trên mạng, tôi đã tổng hợp được một số cách nhận dạng và kỷ thuật cài đặt thuật toán tìm kiếm nhị phân để giải quyết các bài toán tìm kiếm một cách tối ưu – Kỷ thuật “chặt nhị phân”. Chính vì những lý do trên mà tôi lựa chọn đề tài Kỷ thuật “chặt nhị phân” trong bài toán tìm kiếm để tìm hiểu và vận dụng vào quá trình bồi dưỡng học sinh giỏi của mình. 1. Cơ sở lý luận Bản chất của kỷ thuật “chặt nhị phân” là thuật toán tìm kiếm nhị phân được trình bày ở phần thuật toán, sách giáo khoa tin học lớp 10. Bài toán cơ sở như sau: Cho dãy số nguyên A tăng dần và 1 số nguyên K. Đưa ra chỉ số i mà Ai=k hoặc thông báo không có số hạng nào của dãy A có giá trị bằng k. Ý tưởng: Sử dụng tính chất dãy A là dãy số tăng dần, ta tìm cách thu hẹp nhanh phạm vi tìm kiếm sau mỗi lần so sánh khóa với số hạng được chọn. Để làm điều đó ta chọn số hạng Agiua ở giữa dãy để so sánh với K, trong đó Giua=N+1 div 2. Khi đó chỉ xảy ra một trong ba trường hợp sau: Nếu Agiua=k thì giua là chỉ số cần tìm. Việc tìm kiếm kết thúc. Nếu Agiua>k thì việc tìm kiếm tiếp theo chỉ xét trên dãy A1, A2, …, Agiua1 (Phạm vi tìm kiếm mới bằng khoảng một nửa phạm vi tìm kiếm trước đó). Nếu Agiua103 mà thuật toán tìm kiếm tuần tự bị bắt các lỗi chạy quá thời gian quy định. Tuy nhiên chỉ áp dụng tìm kiếm nhị phân khi dãy đã sắp xếp nên chúng ta thường sử dụng thuật toán sắp xếp nhanh (Qsort) với độ phức tạp O(NlogN) để sắp xếp dãy trước đó. 2. Cơ sở thực tiễn. Hầu hết các học sinh sau khi học xong thuật toán tìm kiếm nhị phân chỉ áp dụng được vào giải các bài toán có yêu cầu tương tự. Một phần vì nguồn tài liệu tham khảo, tổng hợp các dạng bài liên quan để học sinh áp dụng hầu như không có. Do đó học sinh không được trải nghiệm, hình thành tư duy và áp dụng thuật toán này vào giải các bài toán. Trong quá trình tham gia các diễn đàn về lập trình, các website dạy lập trình như spoj, upcoder, codeforces tôi đã có nhiều cơ hội để tìm tòi và áp dụng kỷ thuật chặt nhị phân vào để giải quyết các bài toán. Từ đó tôi mong muốn có một nguồn tài liệu để đồng nghiệp, học sinh khá, giỏi tham khảo và tìm hiểu cũng như rèn luyện kỷ thuật này vào quá trình dạy, học và lập trình. 3. Kỷ thuật “Chặt nhị phân” 3.1. Hiệu quả của chặt nhị phân. Để hiểu rõ được sự cần thiết của kỷ thuật “chặt nhị phân”, đầu tiên tôi đưa ra một số bài toán và cách suy nghĩ, thuật toán và chương trình của học sinh. Sau đó phân tích về độ lớn của dữ liệu input và độ phức tạp thuật toán. Cuối cùng là so sánh với chương trình giải quyết bài toán đó khi áp dụng kỷ thuật “chặt nhị phân”. Bài 1: Cho dãy A có N số. Tìm số lượng các số có giá trị nhỏ hơn số nguyên M. Dữ liệu vào: Tệp ‘slbehon.inp’ Dòng đầu tiên chứa số nguyên N cho biết số lượng phần tử của mảng A. Dòng thứ hai chứa N số nguyên cách nhau. Dòng thứ ba chứa số lượng Test Q. Mỗi dòng Q tiếp theo chứa số nguyên M. Dữ liệu ra: Tệp ‘slbehon.out’: Đối với mỗi truy vấn số lượng các số có giá trị nhỏ hơn M cho test đó. Giới hạn: 1 ≤ N ≤ 105 1 ≤ A i ≤ 109 1 ≤ Q ≤ 105 1 ≤ M ≤ 105 Slbehon.inp Slbehon.out 5 1 4 10 5 6 4 2 3 5 11 1 1 2 5 Cách 1: Nhìn qua đây là một bài toán đơn giản và học sinh thường giải theo cách sau đây: Xây dựng 1 hàm để đếm số lượng phần tử trong mảng A có giá trị bé hơn M, hàm này được viết thường là duyệt tuần tự từ A1 đến AN, so sánh Ai với M và tăng biến lưu giá trị đếm. Chương trình được viết như sau: program slbehonc1; const fi=slbehon.inp; fo=slbehon.out; nmax=100000; var a:array1..nmax of longint; n,m,q:longint; f,f1:text; function dem(m:longint):longint; var i:longint; begin dem:=0; for i:=1 to n do if ai