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

Tiểu luận Tìm Kiếm Nhị Phân BINARY SEARCH

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 (279.76 KB, 27 trang )

SỞ GD&ĐT THÁI NGUYÊN
TRƯỜNG THPT CHUYÊN THÁI NGUYÊN

BÀI TIỂU LUẬN MÔN TIN HỌC
Tên đề tài:

TÌM KIẾM NHỊ PHÂN
Nhóm thực hiện:
1. Phạm Thị Lan Anh
2. Đồng Thị Thương
3. Vũ Thu Phương
Học sinh lớp: Tin 11 - K26

Thái Nguyên, tháng 12/2015


Tìm hiểu về thuật toán tìm kiếm nhị phân( Binary search)

MỤC LỤC

MỤC LỤC............................................................................................................2
LỜI NÓI ĐẦU......................................................................................................3
NỘI DUNG...........................................................................................................4
CHƯƠNG I: ĐẶT VẤN ĐỀ..............................................................................................................4
CHƯƠNG II: CƠ SỞ LÍ THUYẾT VÀ BÀI TẬP MINH HỌA................................................................5
A - CƠ SỞ LÍ THUYẾT................................................................................................................5
B - BÀI TẬP MINH HỌA.............................................................................................................9
CHƯƠNG III: ỨNG DỤNG VÀ PHÁT TRIỂN..................................................................................12

KẾT LUẬN CHUNG........................................................................................26
DANH MỤC TÀI LIỆU THAM KHẢO.........................................................27



2


Tìm hiểu về thuật toán tìm kiếm nhị phân( Binary search)

LỜI NÓI ĐẦU
Thế kỷ 21 được coi là kỷ nguyên của Công nghệ thông tin. Các nhà khoa học
khẳng định rằng chưa có một ngành khoa học - công nghệ nào lại có nhiều ứng dụng
như công nghệ thông tin. Nổi bật trong đó là ngành khoa học máy tính - ngành nghiên
cứu các cơ sở lý thuyết về thông tin và tính toán cùng sự thực hiện và ứng dụng của
chúng trong các hệ thống máy tính. Khi tìm hiểu ngành này, chúng ta dễ dàng bắt gắp
các bài toán yêu cầu tìm kiếm (tìm một phần tử trong một danh sách), ví dụ như trong
một danh bạ điện thoại có thể tìm kiếm số điện thoại của một người theo tên người đó.
Để giải những bài toán như vậy, chúng ta có rất nhiều cách khác nhau. Hiểu đơn giản,
mỗi cách đó là một phương pháp tìm kiếm. Ở đây chúng ta đề cập đến các phương
pháp tìm kiếm trong ngôn ngữ lập trình Pascal cũng chính là những thuật toán tìm
kiếm. Có nhiều thuật toán tìm kiếm, đơn giản nhất là thuật toán Tìm kiếm tuyến tính.
Thuật toán này kiểm tra từng phần tử trong danh sách theo thứ tự của danh sách đó. Có
thể sử dụng thẳng cho một danh sách bất kỳ mà không cần tiền xử lý. Đối với các danh
sách lớn, đòi hỏi các thuật toán tốt hơn với độ phức tạp nhỏ hơn. Trong đó tiêu biểu là
Thuật toán Tìm kiếm nhị phân (hay còn gọi là chặt nhị phân). Qua hiểu biết của
chúng em đây là một thuật toán cao cấp hơn hẳn tìm kiếm tuyến tính nhưng nó đòi hỏi
danh sách phải được sắp xếp từ trước, lại có ứng dụng khá nhiều. Vì vậy, nhóm em
muốn cùng tìm hiểu sâu hơn về thuật toán này và làm rõ những vấn đề liên quan đến
nó qua chính kiến thức của mình, qua sách vở và các tài liệu liên quan. Những kiến
thức này sẽ được trình bày bằng bài tiểu luận gồm 3 chương với các nội dung tìm hiểu
là vấn đề thực trạng, cơ sở lí thuyết, bài tập minh họa, ứng dụng và phát triển. Bài tiểu
luận này sẽ không tránh khỏi những sai sót, mong thầy và các bạn sẽ nhiệt tình đóng
góp ý kiến để giúp chúng em hiểu biết thêm trong lĩnh vực này.

Em xin trân thành cảm ơn!

3


Tìm hiểu về thuật toán tìm kiếm nhị phân( Binary search)
NỘI DUNG
CHƯƠNG I: ĐẶT VẤN ĐỀ
Trong ngành khoa học máy tính, một giải thuật tìm kiếm là một thuật toán lấy
đầu vào là một bài toán và trả về kết quả là một lời giải cho bài toán đó, thường là sau
khi cân nhắc giữa một loạt các lời giải có thể. Hầu hết các thuật toán được nghiên cứu
bởi các nhà khoa học máy tính để giải quyết các bài toán đều là các thuật toán tìm
kiếm. Tập hợp tất cả các lời giải có thể đối với một bài toán được gọi là không gian
tìm kiếm. Như chúng ta đã biết, hiện nay có rất nhiều các bài toán yêu cầu tìm kiếm
cũng như các thuật toán tìm kiếm. Tuy nhiên, những thuật toán đơn giản, dễ cài đặt chỉ
đáp ứng được những yêu cầu của bài toán với dữ liệu nhỏ và có thời gian thực thi cao
(như tìm kiếm tuyến tính). Còn những thuật toán tốt hơn hẳn thì lại có những mặt hạn
chế là rất khó cài đặt đặc biệt là gây nhiều khó khăn cho những người mới nhập môn
(như thuật toán Tìm kiếm nội suy hay Giải thuật Grover). Chính vì vậy, vấn đề đặt ra
là chúng ta phải có một thuật toán có những đặc tính hơn hẳn nhiều thuật toán khác mà
đặc biệt phải không quá khó hiểu hay khó sử dụng. Thuật toán Tìm kiếm nhị phân
(Binary search) hay còn gọi đơn giản là chặt nhị phân rất thích hợp cho yêu cầu nói
trên. Tuy nhiên, thuật toán này còn có một vài nhược điểm nhỏ và sử dụng thuật toán
này đôi khi là không có lợi, vậy chúng ta cùng đi tìm hiểu kĩ hơn về “ Thuật toán tìm
kiếm nhị phân”.

4


Tìm hiểu về thuật toán tìm kiếm nhị phân( Binary search)


CHƯƠNG II: CƠ SỞ LÍ THUYẾT VÀ BÀI TẬP MINH HỌA
A - CƠ SỞ LÍ THUYẾT
1.

Định nghĩa và khái niệm tìm kiếm
Tìm kiếm là một đòi hỏi rất thường xuyên trong các ứng dụng tin học. Bài toán

tìm kiếm có thể phát biểu như sau:


Cho một dãy gồm n bản ghi r[1..n]. Mỗi bản ghi r[i] (1 ≤ i ≤ n) tương ứng với

một khoá k[i]. Hãy tìm bản ghi có giá trị khoá bằng X cho trước. X được gọi là khoá
tìm kiếm hay đối trị tìm kiếm (argument).

Công việc tìm kiếm sẽ hoàn thành nếu như có một trong hai tình huống sau xảy
ra:

• Tìm được bản ghi có khoá tương ứng bằng X, lúc
đó phép tìm kiếm thành công.
• Không tìm được bản ghi nào có khoá tìm kiếm bằng

2.


X cả, phép tìm kiếm thất bại.
Sử dụng 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
Phép có thể áp dụng trên dãy khoá đã có thứ tự: k[1] ≤ k[2] ≤ … ≤ k[n].Giả sử


ta cần tìm trong đoạn k[left...right] với khoá tìm kiếm là X, trước hết ta xét khoá nằm
giữa dãy k[mid] với mid = (left + right) div 2;
• Nếu k[mid] < X thì có nghĩa là đoạn từ k[left] tới k[right] chỉ chứa toàn khoá <
X, ta tiến hành tìm kiếm tiếp với đoạn từ k[mid+1] tới k[right].
• Nếu k[mid] > X thì có nghĩa là đoạn từ k[mid] tới k[right] chỉ chứa toàn khoá >
X, ta tiến hành tìm kiếm tiếp với đoạn từ k[left] tới k[mid-1].
• Nếu k[mid] = X thì việc 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 đến một bước nào đó, đoạn tìm kiếm là rỗng
(left>right).

5


Tìm hiểu về thuật toán tìm kiếm nhị phân( Binary search)



Sơ đồ các bước thực hiện thuật toán tìm kiếm nhị phân (Binary search):

Nhập N, a1, a2, …, aN và k

Đầu  1; Cuối  N

Giữa[(Đầu + Cuối)/2]

Đ

a[giữa]=k
S

Đ
a[giữa]>k

Cuối  Giữa - 1

S
Đầu  Giữa +1

Đầu > Cuối

Đưa ra Giữa; KT
Thông báo dãy A không có
số gạng có giá trị bằng k;
KT

6

S


Tìm hiểu về thuật toán tìm kiếm nhị phân( Binary search)

{Tìm kiếm nhị phân trên dãy khoá k[1] ≤ k[2] ≤ … ≤ k[n]; hàm này thử tìm xem trong
dãy có khoá nào = X không, nếu thấy nó trả về chỉ số của khoá ấy, nếu không thấy nó
trả về 0}
Function BinarySearch(X: TKey): Integer;
Var left, right, mid: Integer;
begin
left := 1;
right := n;

while left ≤ right do
begin
mid := (left + right) div 2;
If k[mid] = X then
Begin
BinarySearch := mid;
Exit;
end;
if k[mid] < X then left := mid + 1 else right:= mid - 1;
end;
BinarySearch := 0;
end;

7


Tìm hiểu về thuật toán tìm kiếm nhị phân( Binary search)

2.1. Phân tích đánh giá
 Người ta đã chứng minh được độ phức tạp tính toán của thuật toán trong trường hợp
tốt nhất là O(1), trong trường hợp xấu nhất là O(lg n) và trong trường hợp trung bình là
O(lgn). Tuy nhiên, ta không nên quên rằng trước khi sử dụng, dãy khoá phải được sắp
xếp rồi, tức là thời gian chi phí cho việc sắp xếp cũng phải tính đến. Nếu dãy khoá
luôn luôn biến động bởi phép bổ sung hay loại bớt đi thì lúc đó chi phí cho sắp xếp lại
nổi lên rất rõ làm bộc lộ nhược điểm của phương pháp này.
 Đánh giá giải thuật, ta có bảng so sánh sau:

Trường hợp

Số lần so sánh


Giải thích

Tốt nhất

1

Phần tử giữa mảng có giá trị x

Xấu nhất

Log2n

Không có x trong mảng

Trung bình

Log2

Giả sử xác suất các phần tử trong mảng nhận giá trị x
là như nhau.

Bảng 1: Đánh giá giải thuật của thuật toán tìm kiếm nhị phân

8


Tìm hiểu về thuật toán tìm kiếm nhị phân( Binary search)

B - BÀI TẬP MINH HỌA

Bài toán 1: Cho 1 dãy gồm n phần tử: A1, A2, ... An-1, An. Các phần tử được sắp xếp
theo thứ tự tăng dần. Cần kiểm tra xem 1 khoá x=key cho trước có tồn tại trong dãy
không.
Dữ liệu:
• Dòng 1: Ghi 2 số nguyên n, m.
• N dòng tiếp theo: Mỗi dòng ghi 1 số nguyên Ai
• M dòng tiếp theo: Mỗi dòng ghi 1 khoá key
Kết quả: Gồm m dòng
• Nếu tìm thấy ghi vị trí tương ứng của khóa key trong dãy A
• Nếu không tìm thấy ghi -1
Giới hạn:
1 <= n <= 105
1 <= m <= 104
|Ai| < 231
EXAMPLE:
KEY.INP

KEY.OUT

73

5

1

-1

3

-1


5
7
9
9


Tìm hiểu về thuật toán tìm kiếm nhị phân( Binary search)
10
100
9
1000
6

Ý tưởng: Áp dụng thuật toán tìm kiếm nhị phân.
Code:
const fi='KEY.inp'; fo='KEY.out';
type mang=record gt,cs:longint; end;
var a:array[1..1000000] of mang;
n,m:longint;
procedure solve(t:longint);
var l,r,mid:longint;
begin
l:=1;r:=n;
while l<=r do
begin
mid:=(l+r) div 2;
if a[mid].gt>t then r:=mid-1
else if a[mid].gtelse

begin
10


Tìm hiểu về thuật toán tìm kiếm nhị phân( Binary search)
writeln(a[mid].cs);exit;
end;
end;
writeln(-1);
end;
procedure readf;
var i,t:longint;
begin
assign(INPUT,fi);reset(INPUT);assign(OUTPUT,fo);
rewrite(OUTPUT);readlN(n,m);
for i:=1 to n do
begin
read(a[i].gt); a[i].cs:=i;
end;
for i:=1 to m do
begin
read(t);solve(t);
end; close(OUTPUT);
end;
BEGIN
readf;
END.
11



Tìm hiểu về thuật toán tìm kiếm nhị phân( Binary search)

CHƯƠNG III: ỨNG DỤNG VÀ PHÁT TRIỂN
 Các bài toán ứng dụng thuật toán tìm kiếm nhị phân:
Bài toán 2: Biết rằng căn bậc N của một số S là một số nguyên <10 6. Tìm căn bậc N
của S
• Input: CANBACN.INP có dạng:
o Dòng 1 là số N (N ≤ 100)
o Dòng 2 là số S (0 ≤ S ≤ 1060)
• Output: CANBACN.OUT có dạng:
o Gồm 1 dòng duy nhất là căn bậc N của số S
EXAMPLE:
CANBACN.INP
4

CANBACN.OUT
3

81

Ý tưởng:
Cmin = 0, Cmax = 106 . Output sẽ nằm trong đoạn [Cmin , Cmax] .
Đặt Ctg = (Cmin + Cmax) div 2.
Tính A = CtgN. Để tính A ta dùng thuật toán nhân số lớn.
o Nếu A>S thì tìm kiếm trong đoạn [Ctg+1, Cmax]
o Nếu Ao Nếu A=S thì căn bậc N của S chính là Ctg
Tiếp tục tìm kiếm cho tới khi Cmin> Cmax

12



Tìm hiểu về thuật toán tìm kiếm nhị phân( Binary search)
Code:
{$H+}
const max= 100;
fi= 'CANBACN.inp';
fo = 'CANBACN.out';
var s : string;

n : integer;

cmin, cmax, ctg: longint;
procedure

Readf;

Begin
assign(INPUT,fi); reset(INPUT); readln(n);
readln(s); close(INPUT);
End;
Function

nhan(x:string; so: longint): string;

var nho, tich : longint;
k : integer; y : string;
begin
y:='';


nho:=0;

for k:=length(x) downto 1 do
begin
tich:= so*(ord(x[k])-48)+nho;
y:= chr(tich mod 10+48)+y;
nho:= tich div 10;
end;
while nho>0 do
begin
y:= chr(nho mod 10+48) + y;
nho:= nho div 10;
end;
13


Tìm hiểu về thuật toán tìm kiếm nhị phân( Binary search)
nhan:= y;
end;
Function kiemtra : integer;
var

kq : string;

k : integer;

Begin
kq:= '1';
for k:=1 to n do kq:= nhan(kq,ctg);
If


length(kq)=length(s) then

begin
if kq=s then kiemtra:=0
else
if kq>s then kiemtra:=1
else kiemtra:=2;
end
else
if length(kq)>length(s) then kiemtra:=1 else kiemtra:=2;
end;
Procedure
Var

solve;

cmin,cmax:longint;

Begin
cmin:=0; cmax:=trunc(1e6);
repeat
ctg:=(cmin+cmax) div 2;
case kiemtra of
0 : exit;
2 : cmin:=ctg+1;
1 : cmax:=ctg-1
end;
until cmin>cmax;
14



Tìm hiểu về thuật toán tìm kiếm nhị phân( Binary search)
End;
BEGIN
readf;
solve; Assign(OUTPUT,fo); Rewrite(OUTPUT);
writeln(ctg); Close(OUTPUT);
END.
Bài tập 3: Có n người, n việc (1 < n ≤ 200). Người thứ i thực hiện công viêc j mất
C[i,j] đơn vị thời gian. Giả sử tất cả bắt đầu vào thời điểm 0, hãy tìm cách bố trí mỗi
công việc cho mỗi người sao cho thời điểm hoàn thành công việc là sớm nhất có thể.
• Dự liệu vào trong file CONGVIEC.inp có dạng :
o Dòng đầu: N
o Tiếp theo là ma trận C[i,j] (thuộc kiểu Integer)
• Output ra file CONGVIEC.out :
o Ghi thời điểm sớm nhất hoàn thành.
EXAMPLE:
CONGVIEC.inp

CONGVIEC.out

4

5

10

10


10

2

10

10

3

10

4
10

10
5

10

10

10
10

Ý tưởng:
Sử dụng chặt nhị phân thời gian nhỏ nhất thỏa mãn, giả sử đang chặt tới thời
điểm mid, xây dựng một đồ thị gồm các cạnh có trọng số <=mid, sau đó tìm xem có
thể ghép N công việc cho N người hay không (sử dụng kiến thức cặp ghép). Nếu thỏa
mãn thì chặt nhỏ thời gian thỏa mãn, ngược lại chặt tăng thời gian thỏa mãn.

Code:

15


Tìm hiểu về thuật toán tìm kiếm nhị phân( Binary search)
const
fi='CONGVIEC.inp';
fo=’CONGVIEC.out’; nmax=201;
var

n, dau,cuoi,mid:integer;
a:array[0..nmax+1,0..nmax+1] of integer;
Q:array[0..nmax*nmax] of integer;
tr,MatchX,MatchY:array[0..nmax] of integer;

procedure
var

Readf;

i,j:integer;

Begin
Assign(INPUT,fi); reset(INPUT); readln(n);
For i:=1 to n do
For j:=1 to n do
read(a[i,j]); close(INPUT);
End;
procedure


them(x:integer);

begin
inc(cuoi); q[cuoi]:=x;
end;
function

lay:integer;

begin
lay:=q[dau]; inc(dau);
end;
Function BFS:integer;
var

i,j,u,v:integer;

Begin
for i:=1 to n do
tr[i]:=0;
dau:=1;cuoi:=0;
16


Tìm hiểu về thuật toán tìm kiếm nhị phân( Binary search)
for i:=1 to n do
if MatchX[i]=0 thenthem(i);
while dau<=cuoi do
begin

u:=lay;
for v:=1 to n do
if (a[u,v]<=mid)and (tr[v]=0) then
begin
tr[v]:=u;
if MatchY[v]=0 thenexit(v);
them(MatchY[v]);
end;
end;
EXIT(0);
end;
procedure enlager(u:integer);
var

v,next:integer;

begin
repeat
v:=tr[u];
next:=Matchx[v];
matchx[v]:=u;
Matchy[u]:=v;
u:=next;
until u=0;
end;
Function slove :boolean;
var

i,j,d: integer;


begin
17


Tìm hiểu về thuật toán tìm kiếm nhị phân( Binary search)
for i:=1 to n do
begin
Matchx[i]:=0;
Matchy[i]:=0;
end;
repeat
d:=bfs;
if d<>0 then Enlager(d);
until d=0;
for i:=1 to n do
if Matchx[i]=0 then exit(false);
exit(true);
end;
procedure xuli;
var

i,j:integer;

begin
i:=0;j:=maxint;
while ibegin
mid:=(i+j) shr 1;
if
then j:=midelse


i:=mid+1;
end;

Assign(OUTPUT,fo); Rewrite(OUTPUT);
writeln(i); Close(OUTPUT);
end;
begin
Readf;
Xuli;
18

Slove


Tìm hiểu về thuật toán tìm kiếm nhị phân( Binary search)
End.
Bài tập 4: DÃY TĂNG DÀI NHẤT
Cho một dãy gồm N số nguyên (1 ≤N ≤30000). Hãy tìm dãy con tăng dài nhất trong
dãy đó. In ra số lượng phần tử của dãy con. Các số trong phạm vi longint.
Input : LIS.INP
• Dòng đầu tiên gồm số nguyên N.
• Dòng thứ hai gồm N số mô tả dãy.
Output : LIS.OUT
Gồm một số nguyên duy nhất là đáp số của bài toán
LIS.INP
5

LIS.OUT
3


21435
Ý tưởng:
Dùng chặt nhị phân, với h[i] là vị trí của số hạng nhỏ nhất của các dãy con tăng
có độ dài là i. Gọi h[i] là vị trí của số hạng có a[h[i]] là nhỏ nhất trong số các dãy con
tăng có độ dài là i. Ban đầu h[1] = 1, res là độ dài cần tìm, ban đầu res = 1, ta duyệt
từ 2 -> n, đến vị trí i thì đảm bảo nó là một phần tử mới đối với các dãy con trước đó
đã kiểm và cập nhật, đồng thời ta sẽ cập nhật lại các trạng thái mới cho vị trí. Đồng
thời h[1] < h[2] < h[3] <… < h[n].
có 3 trường hợp sau :
1 / a[i] < a[h[1]] thì xem như nó chẳng thể nào gia nhập vào dãy mới và nó sẽ được tạo
mới cho h[1].
2 / a[i] > a[h[res]] thì phần tử này góp phần làm dãy res dài thêm, nên ta cập nhật lại
res và mảng H.
3 / Trường hợp còn lại (a[h[1]] <= a[i] <= a[h[res]]) thì ta sẽ tìm dãy có độ dài là mid
sao cho a[h[mid]]19


Tìm hiểu về thuật toán tìm kiếm nhị phân( Binary search)
nhị phân trong đoạn 1->res cho mid, vị trí res là độ dài tớn nhất hiện tại
{ l = 1 ; r = res ; mid = (l+r+1)/2 … } xem code
Nếu đã tìm xong rồi và (a[i] > a[h[mid]] (thỏa điều kiện ban đầu của ta) đồng thời (a[i]
< a[h[mid+1]])
( có thêm điều kiện này giống như trường hợp 1 để tạo cho nó min nhất).
Code:
const fi='LIS.inp';
fo='LIS.out';
var


maxd=

30001;

a:

array[0..maxd] of longint;

l:

array[0..maxd] of integer;

n:

longint;

d:

longint;

procedure Readf;
var i:longint;
begin
assign(INPUT,fi); reset(INPUT);
readln(n);
for i:=1 to n do
read(a[i]); close(INPUT);
end;
procedure xuli;
var i,k,dau,cuoi:longint;

begin
l[1]:=1;d:=1;
for i:=2 to n do
if a[i]>a[l[d]] then
begin
inc(d); l[d]:=i;
20


Tìm hiểu về thuật toán tìm kiếm nhị phân( Binary search)
end
else
begin
dau:=1; cuoi:=d;
while daubegin
k:=(dau+cuoi) div 2;
if a[l[k]]else cuoi:=k;
end;
l[dau]:=i;
end;
end;
procedure Writef;
begin
Assign(OUTPUT,fo);
Close(OUTPUT);
end;
BEGIN
Readf;

xuli;
Writef;
END.

21

Rewrite(OUTPUT);

write(d);


Tìm hiểu về thuật toán tìm kiếm nhị phân( Binary search)

 Kĩ thuật duyệt phân tập:
Một kĩ thuật cũng khá hay khi áp dụng binary search, đó là kĩ thuật phân tập.
Trong việc lập trình cho máy tính, phương pháp duyệt toàn bộ các cấu hình để tìm
phương án tối ưu hay đếm số lượng các cấu hình thỏa mãn một điều kiện nào đó, là
một trong những phương pháp quan trọng.
Duyệt toàn bộ là phương pháp liệt kê tất cả các phần tử của một tập hợp D hữu
hạn nào đó, từ đó chỉ ra một phần tử thoả mãn tiêu chí tối ưu hoặc là đếm số lượng các
phần tử thoả mãn yêu cầu nào đó. Cách tư duy này xuất phát từ tập hợp D là hữu hạn.
Có thể nói đây là cách tư duy đơn giản dễ viết chương trình, là phýõng án lập
trình đầu tiên mà mọi học sinh khi bắt đầu học lập trình đều làm quen. Các phương
pháp duyệt toàn bộ thường gặp: duyệt toàn bộ bằng cách sử dụng các vòng lặp lồng
nhau, duyệt quay lui.
Tuy nhiên có thể thấy rằng phương pháp này còn hạn chế khi số lượng các phần
tử của tập D lớn. Nó thể hiện ở chỗ thời gian tính toán để cho ra output thường không
chấp nhận được. Do đó trong phương pháp duyệt toàn bộ cần phải bổ sung các phương
pháp cho phép bỏ qua hoặc gộp một số phần tử. Điều này cải thiện đáng kể thời gian
thực hiện chương trình. Một số phương pháp duyệt cải tiến được đưa ra: duyệt ưu

tiên,duyệt nhánh cận, duyệt bằng cách chia đôi tập hợp..
Trong việc chia đôi tập hợp, hay phân tập chính là việc thay vì ta duyệt qua một tập
hợp, ta chia thành hai hay nhiều tập hợp khác nhau và duyệt từng tập hợp sẽ giúp làm
giảm độ phức tạp của thuật toán xuống đáng kể. Sau đây là một ví dụ để thấy rõ cách
áp dụng thuật toán tìm kiếm nhị phân vào kĩ thuật phân tập:

Bài tập 5: VECTOR
Trong mặt phẳng tọa độ có N véc tơ.Mỗi một véc tơ được cho bởi hai chỉ số x và y.
Tổng của hai véc tơ (xi, yi) và (xj, yj) được định nghĩa là một véc tơ (xi + xj, yi + yj).

22


Tìm hiểu về thuật toán tìm kiếm nhị phân( Binary search)
Bài toán đặt ra là cần chọn một số véc tơ trong N véc tơ đã cho sao cho tổng của các
vec tơ đó là véc tơ (U, V).7u8
Yêu cầu: Đếm số cách chọn thoả mãn yêu cầu bài toán đặt ra ở trên.
Input : VECTOR.INP
• Dòng thứ nhất ghi số N (0 ≤ N ≤ 30).
• N dòng tiếp theo, dòng thứ i ghi các số nguyên xi, yi lần lượt là hai chỉ số của
véc tơ thứ i. (|xi|, |yi| ≤ 100).
• Dòng cuối cùng ghi số hai số nguyên U V (|U|, |V| ≤ 109).
Output: VECTOR.OUT
• Gồm một số duy nhất là số cách chọn thoả mãn.
Example
VECTOR.INP
4

VECTOR.OUT
4


0 0
-1 2
2 5
3 3
2 5
Ý tưởng:
Nếu duyệt tổ hợp của N Vector thì độ phức tạp thuật toán là O(2^N), với n=30 thì
không thể ăn hết điểm của bài này. Vì vậy cần giảm N xuống, thay bằng thuật toán
duyệt phân tập:
_Chia tập hợp thành 2 tập con là A và B.
_ Duyệt tập A dùng mảng F[i,j] để đếm số cách chọn những vector từ A đề được tổng
(i, j).
_ Duyệt tiếp tập B, với mỗi tổng (a, b) thu được, ta cộng vào biến Res (Result) theo

23


Tìm hiểu về thuật toán tìm kiếm nhị phân( Binary search)
công thức : Res := Res + f[u-a, v-b];
_ Biến res chính là output bài toán.
Code:
const

fi='VECTOR.inp';

fo='VECTOR.out';
nmax=30;
var
B:array[-3000..3000,-3000..3000] of word;

ax,ay:array[0..nmax+1] of longint;
uu,vv,n,res:longint;
procedure try1(i,u,v:longint);
begin
if i>n div 2 then exit;
try1(i+1,u+ax[i],v+ay[i]);
inc(b[u+ax[i],v+ay[i]]);
try1(i+1,u,v);
end;
procedure try2(i,u,v:longint);
begin
if i>n then exit;
res:=res+b[uu-(u+ax[i]),vv-(v+ay[i])];
try2(i+1,u+ax[i],v+ay[i]);
try2(i+1,u,v);
end;
procedure Readf;
var

i,j:longint;
24


Tìm hiểu về thuật toán tìm kiếm nhị phân( Binary search)
begin
assign(INPUT,fi); reset(INPUT);
readln(n);
fillchar(b,sizeof(b),0);
for i:=1 to n do
readln(ax[i],ay[i]);

readln(uu,vv); b[0,0]:=1;
close(INPUT);
end;
BEGIN
Readf; try1(1,0,0);
res:=B[uu,vv]; try2(n div 2+1,0,0);
Assign(OUTPUT,fo); Rewrite(OUTPUT);
writeln(res);
END.

25

Close(OUTPUT);