Tải bản đầy đủ (.doc) (25 trang)

Giải một số bài toán bằng phương pháp tìm kiếm nhị phân giúp nâng cao hiệu quả bồi dưỡng học sinh giỏi

Bạn đang xem bản rút gọn của tài liệu. Xem và tải ngay bản đầy đủ của tài liệu tại đây (202.08 KB, 25 trang )

SỞ GIÁO DỤC VÀ ĐÀO TẠO THANH HOÁ

TRƯỜNG THPT TRIỆU SƠN 3

SÁNG KIẾN KINH NGHIỆM

GIẢI MỘT SỐ BÀI TOÁN BẰNG PHƯƠNG PHÁP TÌM
KIẾM NHỊ PHÂN GIÚP NÂNG CAO HIỆU QUẢ BỒI
DƯỠNG HỌC SINH GIỎI

Người thực hiện: Lê Thị Quỳnh
Chức vụ: Giáo viên
Đơn vị công tác: Trường THPT Triệu Sơn 3
SKKN thuộc lĩnh vực (môn): Tin học

THANH HOÁ NĂM 2019


MỤC LỤC

1. MỞ ĐẦU..........................................................................................................1
1.1. Lý do chọn đề tài........................................................................................1
1.2. Mục đích nghiên cứu..................................................................................1
1.3. Đối tượng nghiên cứu.................................................................................1
1.4. Phương pháp nghiên cứu............................................................................1
2. NỘI DUNG......................................................................................................3
2.1. Cơ sở lý luận...............................................................................................3
2.1.1. Nội dung thuật toán..............................................................................3
2.1.2. Nội dung chương trình bằng NNLT PASCAL.....................................3
2.1.3. Độ phức tạp thuật toán.........................................................................3
2.2. Thực trạng của vấn đề cần giải quyết ........................................................4


2.3. Các giải pháp giải quyết vấn đề..................................................................4
2.3.1. Giải bài toán từ “góc nhìn” tìm kiếm nhị phân....................................4
2.3.2. Phân loại các dạng thực hiện tìm kiếm nhị phân................................14
2.3.2.1. Dạng 1: Tìm kiếm nhị phân trên dãy (mảng) có sẵn....................14
2.3.2.2. Dạng 2: Tìm kiếm nhị phân theo kết quả.....................................17
2.4. Hiệu quả của sáng kiến kinh nghiệm........................................................19
3. KẾT LUẬN, KIẾN NGHỊ............................................................................20
3.1. Kết luận.....................................................................................................20
3.2. Kiến nghị...................................................................................................20
DANH MỤC.......................................................................................................22



1. MỞ ĐẦU
1.1. Lý do chọn đề tài.
Trong các đề thi chọn học sinh giỏi (HSG) của các trường THPT trong Tỉnh,
hoặc đề thi HSG cấp Tỉnh những năm gần đây, có những bài toán kích thước
lớn, nếu giải bằng cách thông thường thì sẽ không tối ưu về mặt thời gian, hoặc
có thể không vét hết các trường hợp xảy ra của bài toán. Tuy nhiên, nếu áp dụng
phương pháp tìm kiếm nhị phân (thường gọi là chặt nhị phân) thì sẽ giải quyết
tốt được tất cả các trường hợp trên.
Quá trình dạy tại các lớp mũi nhọn và ôn thi HSG cấp Tỉnh, tôi đã vận dụng
phương pháp tìm kiếm nhị phân để giúp các em nhìn nhận một bài toán từ nhiều
góc độ khác nhau. Qua đó có thể dễ dàng nhận ra việc áp dụng phương pháp này
để giải bài toán nào đó. Vì vậy, tôi đã chọn đề tài “Giải một số bài toán bằng
phương pháp tìm kiếm nhị phân giúp nâng cao hiệu quả bồi dưỡng học sinh
giỏi” làm sáng kiến kinh nghiệm của mình trong năm học 2018 – 2019 để trao
đổi với đồng nghiệp. Đây là một phương pháp tôi đã thực hiện rất hiệu quả tại
ngôi trường THPT Triệu Sơn 3, đồng thời cũng hy vọng cách làm này sẽ được
hoàn thiện, bổ sung và nhân rộng trong các trường THPT khác trong Tỉnh.

1.2. Mục đích nghiên cứu.
Với lý do chọn đề tài đã trình bày ở trên, tôi mong muốn đề tài của mình sẽ
giúp đỡ phần nào các khó khăn khi nhận dạng bài toán tìm kiếm nhị phân trong
quá trình ôn luyện học sinh giỏi.
- Khảo sát, đánh giá được thực trạng việc bồi dưỡng học sinh tham gia thi học
sinh giỏi cấp Tỉnh của trường Trung học phổ thông Triệu Sơn 3.
- Nhìn nhận, giải quyết một số bài toán bằng phương pháp tìm kiếm nhị phân.
1.3. Đối tượng nghiên cứu.
- Thuật toán tìm kiếm nhị phân.
- Một số bài tập thi HSG các cấp.
- Sự tư duy, ý thức học tập của học sinh ôn thi học sinh giỏi.
1.4. Phương pháp nghiên cứu.
Để thực hiện đề tài này, tôi đã sử dụng các phương pháp:
- Phương pháp nghiên cứu xây dựng cơ sở lí thuyết: Cơ sở lý thuyết là phương
pháp tìm kiếm nhị phân, một số bài toán trong các đề thi các cấp; Sự hứng thú
trong giờ học môn Tin học và ý thức tự học của học sinh đối với môn học.

1


- Phương pháp điều tra khảo sát thực tế, thu thập thông tin: Thông qua kết quả
điều tra mức độ hiểu về thuật toán tìm kiếm nhị phân của học sinh lớp 11 trường
THPT Triệu Sơn 3.
- Phương pháp thống kê, xử lý số liệu: Trên cơ sở các kết quả đạt được, thống
kê các số liệu, xử lí số liệu để so sánh giữa nhóm thực nghiệm và đối chứng.

2


2. NỘI DUNG

2.1. Cơ sở lý luận.
Cho dãy K gồm N phần tử đã được sắp xếp theo thứ tự không giảm. Tìm
xem trong dãy có giá trị nào bằng X hay không?
2.1.1. Nội dung thuật toán.
Giả sử cần tìm X trong đoạn K[L ... R] (L �R), trước hết ta xét khóa nằm
giữa đoạn K[Mid] với Mid = (L + R) div 2;


Nếu K[Mid] < X nghĩa là đoạn K[L ... Mid] chứa toàn khóa < X.
khi đó ta tiến hành tìm kiếm X trên đoạn K[Mid+1 ... R]



Nếu K[Mid] > X nghĩa là đoạn K[L ... Mid] chứa toàn khóa > X.
khi đó ta tiến hành tìm kiếm X trên đoạn K[R ... Mid - 1]



Nếu K[Mid] = X thì tìm kiếm thành công (kết thúc quá trình tìm

kiếm).
Quá trình tìm kiếm sẽ thất bại nếu một bước nào đó đoạn tìm kiếm là rỗng
tức là L > R
2.1.2. Nội dung chương trình bằng NNLT PASCAL.
Function TK_NhiPhan(X: Key): integer;
var L,R,Mid:integer;
Begin
L := 1; R := N;
While (L <= R) do
Begin

Mid := (L + R) div 2;
if K[Mid] = X then
Begin
TK_NhiPhan := Mid;
exit;
end
else if K[Mid] < X then L := Mid + 1
else R := Mid – 1;
end;
TK_NhiPhan := 0;
End;

2.1.3. Độ phức tạp thuật toán.
Người ta chứng minh được độ phức tạp tính toán của thuật toán tìm kiếm
nhị phân trong trường hợp tốt nhất là O(1), trong trường hợp xấu nhất là
O(logN). Phương pháp tìm kiếm nhị phân chỉ thực hiện được với dãy đã được
sắp xếp, nên nếu dãy chưa sắp xếp thì cần phải tính đến thời gian cho việc sắp
xếp lại dãy trước khi áp dụng tìm kiếm nhị phân.
3


2.2. Thực trạng của vấn đề cần giải quyết .
Nhiều học sinh có thể hiểu thuật toán tìm kiếm nhị phân nhưng việc vận
dụng để giải một bài toán bằng phương pháp này thì thực sự chưa hiệu quả, chưa
nhìn nhận được cách giải bài toán bằng phương pháp tìm kiếm nhị phân, nhất là
các bài toán dạng tìm kiếm nhị phân “ẩn” hay nói cách khác là dạng tìm kiếm
nhị phân theo kết quả.
Trong nội dung thi học sinh giỏi Tin học các cấp, có nhiều bài thường có
thể giải với nhiều cách khác nhau, trong các cách đó thì không phải cách nào
cũng có thể giải quyết hết các bộ dữ liệu giới hạn của bài toán, việc hướng đến

giải quyết hết các test từ bé đến lớn với thời gian đảm bảo yêu cầu (thường là
1s) là vấn đề không phải học sinh nào cũng có thể làm được. Một trong những
phương pháp giúp học sinh giải được khá nhiều bài ở mức độ vừa và khó là tìm
kiếm nhị phân.
2.3. Các giải pháp giải quyết vấn đề.
2.3.1. Giải bài toán từ “góc nhìn” tìm kiếm nhị phân.
Mỗi bài toán nêu ra trong đề tài này là những ví dụ cho việc có thể thực
hiện giải quyết bài toán bằng nhiều cách, trong đó có thể sử dụng phương pháp
tìm kiếm nhị phân. Đó cũng là cách có thể thực hiện được với bộ dữ liệu từ bé
đến lớn theo yêu cầu giới hạn của bài toán. Trong đề tài này, tôi chỉ nêu ra các
cách giải theo ý chủ quan, vẫn có thể còn những cách làm khác mà bản thân
chưa biết đến, với những cách làm khác được nêu ra, tôi chỉ nêu cách làm, còn
theo cách tìm kiếm nhị phân thì tôi sẽ nêu cách làm và code bài bằng ngôn ngữ
lập trình Pascal.
 Bài toán 1: Taxi (Nguồn: Đề bài thi HSG cấp Tỉnh Thanh Hóa- năm học
2017-2018).
Trong dịp nghỉ hè các bạn học sinh lớp 12 dự định tổ chức dã ngoại đến
biển Sầm Sơn và sẽ đi bằng taxi. Các bạn được chia thành n nhóm, nhóm thứ i
gồm Si bạn (1 ≤ Si ≤ 4) và mỗi chiếc taxi chở tối đa 4 hành khách. Vậy lớp 12
cần thuê ít nhất bao nhiêu chiếc taxi để chở các nhóm đi, với điều kiện là các
bạn trong nhóm phải ngồi chung taxi (một taxi có thể chở một nhóm trở lên).
Dữ liệu vào: Từ tệp văn bản TAXI.INP gồm:
- Dòng đầu chứa số nguyên n (1 ≤ n ≤ 105) (số lượng các nhóm học sinh)
- Dòng số 2 chứa dãy số nguyên S 1, S2, ..., Sn (1 ≤ Si ≤ 4). Các số nguyên cách
nhau bởi dấu cách với Si là số học sinh trong nhóm thứ i.

4


Dữ liệu ra: Ghi ra tệp văn bản TAXI.OUT là 1 số nguyên duy nhất là số lượng

tối thiểu xe taxi cần thiết để chở tất cả học sinh đến nơi.
Ví dụ:

TAXI.INP

TAXI.OUT

5
4
12433
Hướng dẫn giải
Bài này có thể giải theo hai cách như sau:
Cách 1: Tư duy theo kiến thức toán học. Kết quả bài toán là tổ hợp của các
trường hợp có thể xảy ra của bài toán. Theo cách làm này, học sinh khó lấy hết
các test của bài vì nếu không cẩn thận sẽ không xét hết các trường hợp có thể
xảy ra của bài toán. Thực tế là đã có rất nhiều học sinh bị mất điểm ở bài này
theo cách làm như vậy.
Độ phức tạp của thuật toán theo cách này là O(n)
Cách 2. Tìm kiếm nhị phân:
Bài này cần tìm kiếm nhị phân trên dãy dữ liệu của đề bài, nhưng trước
khi tìm kiếm nhị phân, cần sắp xếp lại dữ liệu của đề bài thành dãy không giảm.
Độ phức tạp của thuật toán theo cách này là O(nlogn)
Bước 1. Sắp xếp dãy số nguyên đã cho theo thứ tự không giảm (sắp xếp mảng
a);
Bước 2. dau←1; cuoi ← n;
Bước 3. Nếu a[dau] +a[cuoi]<=4 thì
a[cuoi] ← a[dau]+a[cuoi] ;
a[dau] ←0;
dau:=dau+1;
ngược lại thì cuoi←cuoi-1;

Bước 4. Nếu dauBước 5. i ← 1;
Bước 5.1. Nếu a[i]<>0 thì d← d+1 và i← i+1, ngược lại thì i← i+1;
Bước 5.2. Nếu i<=n thì quay lại bước 5.1;
Bước 6. Đưa ra d và kết thúc.
Dưới đây là code của bài toán bằng cách tìm kiếm nhị phân:
Program TAXI;
VAR f,g: text;
y,n,dau,cuoi,d: longint;
a: array[1..1000000] of byte;
5


procedure sort(l,r: longint);
var i,j,x,y: longint;
begin
i:=l;
j:=r;
x:=a[(l+r) div 2];
repeat
while a[i]inc(i);
while xdec(j);
if not(i>j) then
begin
y:=a[i];
a[i]:=a[j];
a[j]:=y;
inc(i);

j:=j-1;
end;
until i>j;
if lsort(l,j);
if isort(i,r);
end;
BEGIN assign(f,'TAXI.INP');
reset(f);
assign(g,' TAXI.OUT');
rewrite(g);
readln(f,n);
for y:= 1 to n do read(f,a[y]);
sort(1,n);
dau:= 1;
cuoi:= n;
while dau < cuoi do
begin
if a[dau] + a[cuoi] <= 4 then
begin
a[cuoi]:= a[dau] + a[cuoi];
a[dau]:=0;
dau:= dau+1;
end
else cuoi:= cuoi-1;
end;
for y:= 1 to n do
6



if a[y] <>0 then d:= d+1;
write(g,d);
close(f);
close(g);
END.
 Bài toán 2: Dãy con (Nguồn: Đề thi HSG cấp tỉnh Đà Nẵng năm học 2007
- 2008).
Cho một dãy số nguyên dương a1,a2,...,aN (10 < N < 105), ai <=104 với mọi
i=1..N và một số nguyên dương S (S < 108).
Yêu cầu : Tìm độ dài nhỏ nhất của dãy con chứa các phần tử liên tiếp của dãy
mà có tổng các phần tử lớn hơn hoặc bằng S.
Dữ liệu vào: Đọc từ file SUB.INP gồm 2 dòng, dòng 1 chứa N và S ở dòng đầu.
Dòng 2 chứa các phần tử của dãy.
Dữ liệu ra: Kết quả ghi vào file SUB.OUT, chứa độ dài của dãy con tìm được.
Ví dụ:
SUB.INP

SUB.OUT

10 15
2
5 1 3 5 10 7 4 9 2 8
* Hướng dẫn giải:
Bài toán này có thể giải theo 3 cách sau:
Cách 1: dễ dàng giải bài toán với cách là xét 2 vòng lặp lồng nhau để tìm tất cả
các tổng của các đoạn con đồng thời kết hợp tìm đoạn con có tổng >= S và có số
phần tử ít nhất. Độ phức tạp là O(N 2). Vì vậy, cách làm này sẽ chỉ thực hiện
được đến n<=104.
Cách 2: Sử dụng phương pháp tìm kiếm nhị phân để giải bài toán, độ phức tạp

là theo cách này là O(NlogN):
Gọi T[i] là tổng của các số A[1] đến A[i].
Vì A[i] là các số dương nên dãy T là dãy tăng dần.
Khi đó ta sẽ tiến hành tìm kiếm nhị phân trên dãy T như sau:
* Xét T[i]:
d = 1, c = i-1,
g = (d + c) div 2
Nếu T[i] – T[g] >= S thì kq = min(kq, i – g) và tìm kq tiếp tục ở đoạn bên
phải T[g]
Nếu T[i] – T[g] < S thì tìm kq ở đoạn bên trái T[g].
Dưới đây là code của bài toán bằng cách tìm kiếm nhị phân:

7


Program SUB;
const fi='SUB.IN0';
fo='SUB.OU0';
nmax = 100000;
oo = 100001;
Var A,T:array[0..nmax] of longint;
N,S,kq:longint;
F:text;
procedure doc;
var i:longint;
Begin
assign(F,fi);
reset(F);
T[0] := 0;
Readln(F,N,S);

for i:=1 to N do
Begin
read(F,A[i]);
T[i] := T[i-1] + A[i];
end;
close(F);
end;
function min(a,b:longint):longint;
Begin
if a > b then min := b
else min := a;
end;
procedure xuly;
var i,d,c,g:longint;
Begin
kq := oo;
for i:=1 to N do
Begin
d := 1; c := i-1;
While d <= c do
Begin
g := (d + c) div 2;
if T[i] - T[g] >= S then
Begin
kq := min(kq,i-g);
d := g + 1;
end
else c := g - 1;
end;
end;

8


end;
procedure ghi;
Begin
assign(F,fo);
rewrite(F);
if kq = oo then write(F,0)
else Write(F,kq);
close(F);
end;
BEGIN
doc;
xuly;
ghi;
END.
Cách 3: Bài toán có thể giải với độ phức tạp là O(N).
Xét tổng đoạn T = A[d] + A[d+1] + A[d+2] + …+ A[c]
Nếu T < S thì cần bổ sung thêm giá trị của A[c+1] vào tổng để T có thể >= S
Nếu T <= S thì cập nhật lại kq, vì kết quả là đoạn ngắn nhất nên nếu loại bỏ
A[d] đi để được đoạn ngắn hơn đoạn trước đó.
 Bài toán 3: Lucky number
Chí Phèo thời IT rất yêu thích các số Lucky. Số Lucky là số mà chỉ chứa
các chữ số Lucky (có hai chữ số Lucky là 4 và 7) trong biểu diễn thập phân. Các
số Lucky sắp xếp tăng dần tạo thành dãy số Lucky. Một số số hạng đầu tiên của
dãy số Lucky là: 4,7,44,47,74,77,… Biết Chí có niềm yêu thích như vậy, Thị Nở
liền đố Chí tìm số Lucky thứ K trong dãy. Bài toán thực sự hóc búa với Chí, bạn
hãy giúp anh Chí câu hỏi này nhé!. Biết rằng:
Dữ liệu vào: Từ tệp LUCKY.INP gồm số n (n 109) duy nhất.

Dữ liệu ra: Ghi vào tệp LUCKY.OUT chứa số Lucky tìm được
Ví dụ:
LUCKY.INP
LUCKY.OUT
4
47
Hướng dẫn giải
Bài này có thể giải theo những cách như sau:
Cách 1. Xét lần lượt các số tự nhiên từ 1 đến max. Với mỗi số i, kiểm tra xem
nó có là số may mắn hay không? Cứ như thế cho đến khi nào tìm được số may
mắn thứ n. Độ phức tạp của thuật toán theo cách này là O(n) * độ phức tạp của
hàm kiểm tra số may mắn.
Cách 2. Ta nhận thấy: Có 2k số may mắn có độ dài k :
9


- Số thứ nhất là
- Số thứ hai là
- Số thứ ba là
- Số thứ tư là
- Số thứ năm là
- Số thứ sáu là

4
7
Vậy tổng có 2 số có 1 chữ số, 21 = 22 - 2.
44
47
74
77

Vậy tổng có 22 +21 chữ số = 23 - 2
444
447
474
477
744
747
774
777 Có 8 số có 3 chữ số
3
2
1
4
Với mỗi k=1,2,3...thì Vậy tổng có 2 + 2 + 2 =2 -2
tổng
số lượng các số may
mắn
là 22 -2 , 23 -2, 232, ...Vậy, nếu gọi vị trí của số đó là n thì số thứ n sẽ luôn lớn hơn một số có dạng
2x -2, tức là: 2x -2 ≤ n≤ 2x+1 -2. Ta sẽ duyệt x chạy từ 1 đến 30 (vì 2 31=
1073741824), nếu n nằm giữa khoảng trên thì tìm được 2 điểm đầu cuối
Vì vậy, vị trí đầu cuối để chặt nhị phân là 2x -2 và 2x+1 -2.
Thứ hai, ta thấy các chữ số luôn chia thành hai nửa, số 4 và số 7 nên ta
tìm kiếm nhị phân đoạn này thì ta sẽ tìm ra được chữ số.
Độ phức tạp của thuật toán theo cách này là O(log2x), với 1≤ x≤30
Dưới đây là code của bài toán bằng cách tìm kiếm nhị phân:
Const Fi='luckynum.inp';
Fo=' luckynum.out';
Var F1,F2:text;
F:array[1..30] of longint;
N,i,dau,cuoi,giua,dem:longint;

procedure Nhap;
begin
assign(F1,Fi);
assign(F2,Fo);
reset(F1);
rewrite(F2);
read(F1,N);
10


end;
function Lt(X:byte):longint;
begin
if X=0 then Lt:=1 else Lt:=2*Lt(X-1);
end;
BEGIN
Nhap;
for i:= 1 to 30 do
begin
F[i]:=Lt(i+1)-2;
if F[i]>N then break;
end;
dau:=F[i-1];
cuoi:=F[i];
giua:=(dau+cuoi) div 2;
dem:=0;
while dem<>i do
begin
if N<=giua then write(F2,'4') else write(F2,'7');
inc(dem);

if N<=giua then cuoi:=giua else dau:=giua;
giua:=(dau+cuoi) div 2;
end;
close(F1);
close(F2);
END.
 Bài toán 4: Số ngẫu nhiên. (Nguồn: Đề thi chọn đội tuyển trường năm học
2017-2018 , Trường ĐH SP Vinh).
Cho dãy số nguyên a1,a2,..,an.Số ai được gọi là số k-ngẫu nhiên của dãy
nếu trong k số hạng liên tiếp bất kì của dãy đều có ít nhất một số hạng bằng a i và
k là số nguyên nhỏ nhất thỏa mãn điều kiện này.
Ví dụ: Dãy 1,2,3,1,2,2. Số 1 là số 3-ngẫu nhiên; số 2 là số 3-ngẫu nhiên; số 3 là
số 4-ngẫu nhiên.
Yêu cầu: Tìm k nhỏ nhất để trong dãy có số k – ngẫu nhiên.
Input: Cho trong tệp văn bản RANNUM.INP như sau:
- Dòng đầu ghi số nguyên dương n (N<=105)
- Dòng thứ 2 ghi n số nguyên a1,a2,..an.(|ai|<=103).
Output: Ghi trong tệp văn bản RANNUM.OUT gồm một số k tìm được thỏa
mãn yêu cầu bài toán.
Ví dụ:

RANNUM.INP

RANNUM.OUT
11


6
3
123122

* Hướng dẫn giải:
Cách 1: Bài toán được giải bằng phương pháp tìm kiếm nhị phân. Độ phức tạp
là O(NlogN)
Bước 1: Khởi tạo K = N (Mọi số trong dãy đều là số N – ngẫu nhiên)
Bước 2:
d := 1; c:= k
While d <= c do
Begin
g := (d+c) div 2;
if OK(g) then {Nếu dãy có số g – ngẫu nhiên}
Begin
kq := g; {lưu lại kq}
c := g – 1; {giảm g}
end
else {ngược lại thì tăng g} d := g + 1;
end;
Vấn đề đặt ra là hàm OK(k) – Kiểm tra dãy có số k – ngẫu nhiên phải xử lý thế
nào?
Muốn kiểm tra A[i] có phải là số k – ngẫu nhiên hay không thì chỉ việc kiểm tra
trong mọi đoạn k số liên tiếp có xuất hiện A[i] không.
Dưới đây là code của bài toán bằng cách tìm kiếm nhị phân:
program RANNUM;
const fi='RANNUM.IN0';
fo='RANNUM.OU0';
nmax = 100000;
amax = 1000;
var f:text;
A:array[1..nmax+1] of longint;
dem:array[-amax .. amax] of longint;
N,kq:longint;

procedure doc;
var i:longint;
Begin
assign(f,fi); reset(f);
readln(f,N);
for i:=1 to N do read(f,A[i]);
12


close(f);
end;
function ok(k:longint):boolean;
var i,j:longint;
Begin
fillchar(dem,sizeof(dem),0);
for i:=1 to k do inc(dem[A[i]]);
for i:=K+1 to N do
if dem[A[i]]=0 then dec(dem[A[i-k]])
else if A[i] <> A[i-k] then
Begin
inc(dem[A[i]]);
dec(dem[A[i-k]]);
end;
ok := false;
for i:=-1000 to 1000 do
if dem[i] > 0 then
Begin
ok := true;
exit;
end;

end;
procedure nhiphan;
var g,d,c:longint;
Begin
d := 1;
c := N;
While d <= c do
Begin
g := (d + c) div 2;
if ok(g) then
Begin
kq := g;
c:=g-1;
end
else d := g + 1;
end;
end;
procedure ghi;
Begin
assign(f,fo); rewrite(f);
write(f,kq);
close(f);
end;
BEGIN
13


doc;
nhiphan;
ghi;

END.
Cách 2: Có thể sử dụng thuật toán với độ phức tạp là O(N) để giải quyết bài
toán.
Ta thấy 1 trong k số đầu tiên của dãy sẽ là số k – ngẫu nhiên.
Vì vậy sẽ dùng thêm mảng dem[-1000 .. 1000] để đếm tần số xuất hiện các của
k phần tử đầu tiên trong dãy, khi đó dem[A[i]] > 0 nghĩa là A[i] có thể là số k –
ngẫu nhiên.
Duyệt 1 vòng lặp: i từ k+1 đến N:
+ if dem[A[i]] = 0 then dec(dem[A[i-k]])
{Nếu số A[i] không xuất hiện trong k số từ A[i – k] tới A[i – 1] thì A[i] không là
số k ngẫu nhiên – thì giảm dd[A[i-k]] 1 đơn vị để loại số A[i-k] này ra khỏi dãy
có k số liên tiếp}
+ if (dem[A[i]] > 0) and (dem[A[i]] <> dem[A[i-k]] then
Begin
inc(dem[A[i]]);
dec(dem[A[i-k]]);
end;
{Nếu A[i] xuất hiện trong dãy A[i – k] tới A[i – 1] thì A[i] có thể là số k – ngẫu
nhiên và trong dãy A[i-k+1] đến A[i] có A[i] thì tăng dem[A[i]]}
Duyệt lại lần nữa để kiểm tra xem có dd[i] > 0 hay không? Nếu có thì dãy có số
k – ngẫu nhiên.
2.3.2. Phân loại các dạng thực hiện tìm kiếm nhị phân.
Để biết một bài toán nào đó có thể sử dụng thuật toán tìm kiếm nhị phân
để giải quyết hay không thì có thể qui về hai dạng như sau:
2.3.2.1. Dạng 1: Tìm kiếm nhị phân trên dãy (mảng) có sẵn.
Đối với dạng bài này sẽ đơn giản hơn vì dãy (mảng) các phần tử cần được
sắp xếp lại (hoặc đã được sắp xếp sẵn), yêu cầu bài toán cần chỉ ra kết quả có
thể xuất hiện trong dãy hay không. Với n lớn hơn 10 4, thì không thể duyệt 2
vòng để tìm kết quả vì sẽ quá thời gian qui định (1s). Khi đó, có thể nghĩ đến sắp
xếp bằng quick-sort và tìm kiếm nhị phân. Cụ thể:

Ví dụ 1: Các bài toán đã trình bày ở phần 2.3.1
Ví dụ 2. Hẹn gặp (Nguồn: Đề thi HSG cấp Tỉnh Thanh Hóa năm học 20162017)
14


Thành phố Gloaming (Hoàng hôn) nổi tiếng với đường dẫn vào công
viên thành phố. Các bức tượng tuyệt đẹp theo chủ đề thần thoại Hy lạp – La mã
đặt dọc theo con đường thẳng có một sức hút không cưỡng được với mọi khách
du lịch. Còn khi những tia nắng cuối cùng trong ngày miễn cưỡng rời khỏi bầu
trời thì sương mù dày đặc, như một tấm voan trắng mềm mại từ từ rũ xuống.
Bây giờ đứng cách quá r mét là đã không nhìn thấy mặt nhau và các bức tượng
trở thành nơi lý tưởng cho các đôi nam nữ thanh niên hẹn hò.
James Bond cần gặp gấp 2 điệp viên nội tuyến của mình để nhận các mật
báo khẩn. Không muốn 2 người này nhìn thấy nhau, Bond hẹn gặp mỗi người ở
một bức tượng sao cho khoảng cách giữa chúng lớn hơn r. Trên đường có n bức
tượng, bức tượng thứ i ở vị trí cách đầu con đường di mét i = 1 ÷ n, 1 ≤ d1< d2
< . . .< dn ≤ 109.
Yêu cầu: Hãy xác định James Bond có bao nhiêu cách chọn địa điểm.
Dữ liệu vào: Vào từ file văn bản HENGAP.INP:
- Dòng đầu tiên chứa 2 số nguyên n và r (1 ≤ n ≤ 3×105, 1 ≤ r ≤ 109).
- Dòng thứ 2 chứa n số nguyên d1, d2, . . ., dn.
Kết quả: Đưa ra file văn bản HENGAP.OUT một số nguyên là số cách
chọn địa điểm tìm được.
Ví dụ:

HENGAP.INP
44
1358

HENGAP.OUT

2

Rằng buộc:
Có ½ số test tương ứng với ½ số điểm có n ≤ 104
Có ½ số test tương ứng với ½ số điểm có 104 < n ≤ 3×105
Ý tưởng: (Nội dung này tham khảo trong tài liệu tập huấn giáo viên 2017 )
- Dùng một vòng lặp For – do để duyệt i từ 1 đến n-1, trong đó với mỗi vị
trí i thì ta tìm kiếm nhị phân để tìm địa điểm j xa nhất thỏa mãn r+di < dj.
Ví dụ 3. (Nguồn: Đề bài hội thi chọn GVG Tỉnh Thanh Hóa năm học 20132014)
Xét dãy số nguyên dương khác nhau từng đôi một a 1, a2,...., an. Với số
nguyên x cho trước. Hãy xác định số cặp (ai, aj) thỏa mãn các điều kiện:
- ai +aj =x
- 1 ≤ i Dữ liệu vào: File văn bản BAI3.INP:
15


- Dòng đầu tiên chứa số nguyên dương n
- Dòng thứ hai chứa n số nguyên a 1, a2, ..., an. Mỗi số cách nhau ít nhất một dấu
cách trống
- Dòng thứ ba chứa số nguyên x.
Kết quả ra: File văn bản BAI3.OUT chứa một số nguyên là số cặp tìm được.
Giới hạn: 1≤ ai ≤ 109 , 1 ≤ i ≤ n ≤105 , 1 ≤ x ≤ 2.109.
Ví dụ:
BAI3.INP
9
5 12 7 10 9 1 2 3 11
13

BAI3.OUT

3

Ý tưởng: (Nội dung này tham khảo trong tài liệu tập huấn giáo viên 2017)
- Sắp xếp thành dãy tăng (dùng thuật toán quicksort)
- Thực hiện tìm kiếm nhị phân trên dãy đã sắp xếp.
Ví dụ 3. Ghép cặp
Trong một bữa tiệc, có N người tham dự. Người thứ i có chiều cao là Hi.
Người tổ chức bữa tiệc muốn đếm xem ông có thể ghép được bao nhiêu cặp từ
N người này. Ông là một người khá vui tính, vì không muốn để cho các cặp đôi
trông quá chênh lệch về chiều cao, ông đã đưa ra 1 yêu cầu: Người thứ i và
người thứ j (i ≠ j) có thể ghép cặp được với nhau nếu như thỏa mãn điều kiện
sau: 90% * Hj ≤ Hi ≤ Hj. Nếu có cặp người thứ i đã ghép với người thứ j thì đảo
vị trí ghép của 2 người này, thì đây cũng chỉ tính là 1 cách ghép (ví dụ: nếu có
cách ghép người thứ 2 với người thứ 3 thì cũng giống như ghép người thứ 3 với
người thứ 2)
Với số lượng người tham dự nhỏ ông có thể dễ dàng tính ra được số cặp có
thể ghép, nhưng bữa tiệc có rất nhiều người và việc tính toán của ông trở nên
khó khăn hơn.
Yêu cầu: Hãy giúp ông tính số cặp có thể ghép được.
Dữ liệu: Vào từ file văn bản GHEPCAP.INP gồm:
- Dòng đầu tiên chứa số nguyên dương N là số người tham dự bữa tiệc. (N ≤
105)
- Dòng thứ 2 chứa N số nguyên dương Hi là độ cao của N người. (Hi ≤ 109)
Kết quả: Ghi ra file văn bản GHEPCAP.OUT gồm một dòng duy nhất là kết
quả của bài toán.
Ví dụ:
GHEPCAP.INP

GHEPCAP.OUT


16


6
100 89 90 101 91 99

11

Ý tưởng: (Nội dung này tham khảo trong tài liệu tập huấn Sở GD&ĐT )
+ Sắp xếp tăng dần theo chiều cao
+ Duyệt từ i từ 1 đến n-1 với mỗi vị trí i thì ta chặt nhị phân để tìm người
có vị trí j xa nhất mà thỏa mãn 9*h[j] <= 10*h[i]. Nếu j > i thì ta được thêm số
cặp là j-i.
2.3.2.2. Dạng 2: Tìm kiếm nhị phân theo kết quả.
Nhiều người thường dùng cụm từ “chặt nhị phân ẩn” để nói về cách làm
này. Đây là cách dự đoán vào kết quả có thể xảy ra của bài toán thuộc khoảng
nào, từ đó giới hạn giá trị đầu, giá trị cuối và tìm kiếm nhị phân trên khoảng giá
trị đó để đưa ra kết quả của bài toán. Một số bài toán cụ thể như sau:
Ví dụ 1. Nguồn: />Có N cây gỗ, có chiều cao lần lượt là A[1], A[2], .., A[n]. Bạn cần lấy một
lượng gỗ độ cao tối thiểu là M bằng cách chặt từ N cây theo cách như sau: chặt
tất cả những phần thừa của các cây có độ cao lớn hơn H. Hãy tìm giá trị H lớn
nhất để bạn có thể lấy được lượng gỗ tối thiểu là M.
Dữ liệu: Vào từ file văn bản PTIT126J.INP
+ Dòng 1 chứa 2 số nguyên N (1<=N<=106) và M (1 <= M <= 2.109).
+ Dòng 2 chứa N số nguyên A[1], A[2], …, A[n], là chiều cao mỗi cây gỗ
tương ứng (A[i] <= 109, i=1..N). Giả sử luôn tồn tại cách chặt.
Kết quả: Ghi ra file PTIT126J.OUT số H duy nhất.
Ví dụ:
PTIT126J.INP
47

20 15 10 17
5 20
4 42 40 26 46

PTIT126J.OUT
15
36

Giải thích test ví dụ:
Cây 1 chặt được (20-15)=5. Cây 4 chặt được (17-15)=2. Tổng số gỗ chặt
được nếu H = 15 là 7.
Ý tưởng: Chặt nhị phân theo kết quả. Ta biết rằng kết quả của bài toán nằm
trong khoảng (0, max(a[i])). Với mỗi giá trị là H thì ta kiểm tra xem tổng gỗ chặt
ra có lớn hơn hoặc bằng M hay không. Nếu đúng thì ta lại chặt nhị phân trên
đoạn sau. Nếu sai thì ta lại chặt nhị phân trên đoạn đầu.
Ví dụ 2. Nguồn: />
17


Tại sân bay Nội Bài, một hành khách gồm M người chuẩn bị tham gia
chuyến bay. Vì số lượng khách quá lớn nên điểm kiểm soát của sân bay đã được
tăng lên thành N điểm. Tại điểm kiểm soát thứ i, cần mất T_i (s) để có thể kiểm
tra xong một người (tính cả thời gian đi bộ từ địa điểm xếp hàng tới điểm kiểm
tra này). Các hành khách sắp xếp theo một hàng đợi. Lần lượt từng người vào
một. Hành khách ở đầu hàng đợi được phép đi vào một trạm kiểm soát nào đó
nếu như trạm kiểm soát đó đang trống. Tuy nhiên, người đó cũng có quyền đứng
chờ để đợi một trạm kiểm soát khác trống để đi tới trạm đó, vì có thể giảm thiểu
chi phí thời gian cho cả đoàn (xem ví dụ 1).
Các bạn hãy tính toán xem thời gian nhỏ nhất có thể để đoàn hành khách
kiểm tra xong hành lý là bao nhiêu?

Dữ liệu: Vào từ file P145SUMG.INP gồm:
+ Dòng đầu tiên gồm 2 số nguyên N và M, lần lượt là số quầy gửi đồ và
số vị khách (N <= 105, M <= 109).
+ N dòng tiếp theo, mỗi dòng là số nguyên T_i (1 <= T_i <= 109).
Kết quả: Ghi ra file P145SUMG.OUT đáp số của bài toán.
Ví dụ:
P145SUMG.INP
2 6
7
10

P145SUMG.OUT
28

Giải thích test ví dụ: Có 2 trạm kiểm soát và 6 hành khách.
Tại t = 0, hành khách 1 và 2 bước vào trạm kiểm tra I và II. Tại t = 7, trạm
I trống, và người thứ 3 được phép đi. Tại t = 10, trạm II trống, người thứ 4 bước
vào kiểm tra. Tại t = 14, trạm I trống, người thứ 5 tới kiểm tra. Tại t = 20, trạm
II trống, nhưng hành khách thứ 6 sẽ đợi thêm một chút, tới t = 21, trạm I trống
và hành khách này sẽ tới kiểm tra, tổng chi phí thời gian bằng 28(s).
Ý tưởng:
+ Chặt nhị phân theo kết quả.
+ Kiểm tra xem với mỗi giá trị thời gian là X xem nó có thỏa mãn hay
không. Nếu thỏa mãn thì ta lại chặt nhị phân trên đoạn đầu, còn nếu không thỏa
mãn thì ta lại chặt nhị phân trên đoạn sau.
2.4. Hiệu quả của sáng kiến kinh nghiệm.
Sau hai năm học áp dụng phương pháp này vào ôn luyện thi học sinh giỏi
cấp Tỉnh (năm học 2017-2018 phụ trách chính, năm học 2018-2019 đồng phụ
trách một vài chuyên đề, trong đó có chuyên đề tìm kiếm nhị phân), tôi nhận
thấy các em hứng thú hơn và hiểu rõ hơn nội dung, bản chất của thuật toán tìm

18


kiếm nhị phân. Đặc biệt, các em đã nhìn nhận để giải quyết bài toán bằng
phương pháp này rất hiệu quả. Từ đó, mở ra khả năng hứng thú học tập cho các
nội dung (chuyên đề) khác, cách tư duy bài toán cũng đa dạng và khoa học hơn.
Kết quả thi học sinh giỏi cũng tăng lên. Cụ thể như sau:
* Đối với nhóm học sinh đối chứng:
STT

Họ và tên

Lớp

1
Hà Minh Dũng
11B4
2
Trịnh Việt Đức
11B4
3
Đỗ Phương Nam
11C3
4
Nguyễn Văn Tuấn
11C3
* Đối với nhóm học sinh thực nghiệm:

Kết quả thi HSG
Điểm

Xếp giải
10.0
KK
8.5
Không
6.5
Không
9.0
Không

Năm học
2015-2016
2016-2017

Kết quả thi HSG
Năm học
Điểm
Xếp giải
1
Đào Công Cường
11D3
12.0
KK
2017-2018
2
Lê Thị Hương
11D3
15.0
Ba
3

Hà Văn Đức
11E4
12.5
KK
2018-2019
4
Đào Huy Hiệu
11E4
16.25
Nhì
Như vậy, rõ ràng việc hướng dẫn học sinh giải bài toán bằng phương pháp
tìm kiếm nhị phân đã giúp các em có thể giải quyết triệt để nhiều bài toán ở mức
độ vừa và khó, các em có thể nhìn nhận những bài toán dùng phương pháp tìm
kiếm nhị phân nhanh và chính xác. Từ đó, kết quả thi học sinh giỏi cấp Tỉnh
cũng ngày càng được nâng cao.
STT

Họ và tên

Lớp

Với kết quả có được như trên trong hai năm học liên tục, tôi thiết nghĩ đây là
một cách làm thực sự hiệu quả, góp phần vào thành công của công tác ôn thi học
sinh giỏi môn Tin học của nhà trường.

19


3. KẾT LUẬN, KIẾN NGHỊ
3.1. Kết luận.

Qua việc thực hiện đề tài, tôi nhận thấy tìm kiếm nhị phân là một phương
pháp cần thiết trong việc dạy học lập trình nói chung và ôn thi học sinh giỏi nói
riêng. Với nội dung được cung cấp trong sách giáo khoa lớp 10 thì chỉ mang tính
gợi mở, các em cần được rèn luyện thông qua các bài tập để có thể hiểu rõ bản
chất của thuật toán, biết vận dụng để giải quyết các bài toán bằng phương pháp
này hiệu quả thực sự.
Việc áp dụng thuật toán này cũng đã đem lại hiệu quả thực sự trong việc
ôn thi học sinh giỏi tại đơn vị THPT Triệu Sơn 3: Học sinh tự tin hơn, học tập
tích cực hơn, chủ động hơn, khả năng tư duy tốt hơn và có kết quả cao hơn.
3.2. Kiến nghị.
Đối với giáo viên, phải không ngừng tự học, tự bồi dưỡng, tham khảo các
ý kiến chia sẻ từ đồng nghiệp nhất là về các bài tập, các đề thi học sinh giỏi các
cấp. Từ đó vận dụng vào công tác bồi dưỡng học sinh giỏi đạt hiệu quả cao nhất.
Đối với các cấp lãnh đạo, cần tổ chức hội thảo chuyên đề cho giáo viên bộ
môn Tin học hàng năm để giáo viên có dịp được trao đổi, học hỏi kinh nghiệm,
tìm ra những giải pháp, biện pháp tốt, ý tưởng hay giúp nâng cao chất lượng dạy
học nói chung và ôn thi học sinh giỏi nói riêng.

XÁC NHẬN

Thanh Hóa, ngày 28 tháng 05 năm 2019

CỦA THỦ TRƯỞNG ĐƠN VỊ

Tôi xin cam đoan đây là SKKN của mình viết,
không sao chép nội dung của người khác.
Người viết

LÊ THỊ QUỲNH


20


TÀI LIỆU THAM KHẢO
1. Tin học 10, NXB Giáo Dục, 2006. Tác giả: Hồ Sĩ Đàm, Hồ Cẩm Hà, Trần Đỗ
Hùng, Nguyễn Đức Nghĩa, Nguyễn Thanh Tùng, Ngô Ánh Tuyết.
2. Tin học 11, NXB Giáo Dục, 2007. Tác giả: Hồ Sĩ Đàm, Hồ Cẩm Hà, Trần Đỗ
Hùng, Nguyễn Đức Nghĩa, Nguyễn Thanh Tùng, Ngô Ánh Tuyết.
3.Tài liệu chuyên Tin học quyển 1, NXB Giáo Dục. Tác giả Hồ Sĩ Đàm (chủ
biên), Đỗ Đức Đông, Lê Minh Hoàng, Nguyễn Thanh Tùng.
4. Tài liệu Tập huấn giáo viên 2017 (Tỉnh Thanh Hóa).
5. Tài liệu tập huấn giáo viên năm 2016 Tỉnh Thanh Hóa (Tài liệu lưu hành nội
bộ).
6. Website />
21


DANH MỤC
CÁC ĐỀ TÀI SÁNG KIẾN KINH NGHIỆM ĐÃ ĐƯỢC HỘI ĐỒNG
ĐÁNH GIÁ XẾP LOẠI CẤP PHÒNG GD&ĐT, CẤP SỞ GD&ĐT VÀ CÁC
CẤP CAO HƠN XẾP LOẠI TỪ C TRỞ LÊN

Họ và tên tác giả: Lê Thị Quỳnh
Chức vụ và đơn vị công tác: NTCM Tin học, trường THPT Triệu Sơn 3

TT

1.

2.


3.

Tên đề tài SKKN

Kết quả
Cấp đánh
đánh giá
giá xếp loại
xếp loại
(Phòng, Sở,
(A, B,
Tỉnh...)
hoặc C)
Sở GD&ĐT
C

Sử dụng sơ đồ tư duy nhằm
tạo hứng thú và nâng cao chất
lượng cho học sinh khi dạy
tiết 21 – bài tập, Tin học lớp
11.
Một số kinh nghiệm giáo dục Sở GD&ĐT
ý thức sử dụng Internet và kỹ
năng sống nhằm nâng cao
nhận thức và kết quả học tập
cho học sinh thông qua bài 9
và chương IV Tin học 10.
Hướng dẫn giải một số bài
Sở GD&ĐT

tập trong sách bài tập Tin học
11 nhằm nâng cao kết quả
học tập cho học sinh và lựa
chọn, bồi dưỡng học sinh
giỏi.

Năm học
đánh giá xếp
loại
2012 - 2013

C

2015 – 2016

C

2017 - 2018

----------------------------------------------------

22


×