ỨNG DỤNG PHƯƠNG PHÁP TÌM KIẾM TRONG VIỆC GIẢI CÁC BÀI TOÁN THI HỌC SINH GIỎI MÔN TINHỌC MÃ: TI17 1.. Công việc tìm kiếm sẽ hoàn thành nếu như một trong hai tìnhhuống sau sảy ra: Tìm đư
Trang 1ỨNG DỤNG PHƯƠNG PHÁP TÌM KIẾM TRONG VIỆC GIẢI CÁC BÀI TOÁN THI HỌC SINH GIỎI MÔN TIN
HỌC MÃ: TI17
1 CƠ SỞ LÝ THUYẾT
1.1 Phát biểu bài toán
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 khóa k[i] Hãy tìm một bản ghi có giá trịkhóa bằng X cho trước
X được gọi là khóa tìm kiếm
Công việc tìm kiếm sẽ hoàn thành nếu như một trong hai tìnhhuống sau sảy ra:
Tìm được bản ghi có khóa 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ó khóa tương ứng bằng X,lúc đó phép tìm kiếm thất bại
1.2 Phương pháp tìm kiếm tuần tự
1.2.1 Nội dung thuật toán
Bắt đầu từ bản ghi đầu tiên, lần lượt so sánh khóa tìm kiếmvới khóa tương ứng của các bản ghi trong danh sách, cho tới
Trang 2khi tìm thấy bản ghi mong muốn hoặc duyệt hết danh sách màkhông thấy.
1.2.2 Nội dung chương trình
* Code của ngôn ngữ lập trình PASCAL
Function TK_tuantu(X: Key): integer;
for (int i = 1; i <= n; i++)
if (r[i] == X) return i;{tìm thấ% y X thì tra & ra
vị trí cu &a nó}
return 0;
}
1.2.3 Đánh giá độ phức tạp của thuật toán:
Thuật toán có độ phức tạp tốt nhất là O(1), khi K[1] = X và xấunhất là O(N) khi không tìm được X trong danh sách khóa
Như vậy độ phức tạp của thuật toán là O(N)
1.3 Phương pháp tìm kiếm nhị phân
Phương pháp tìm kiếm nhị phân được áp dụng trên dãy khóa
đã sắp thứ tự Tức là K[1] K[2] K[n]
Trang 31.3.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 taxé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ứatoàn khóa < X khi đó ta tiến hành tìm kiếm X trên đoạnK[Mid+1 R]
Nếu K[Mid] > X nghĩa là đoạn K[L Mid] chứatoàn khóa > X khi đó ta tiến hành tìm kiếm X trên đoạnK[R Mid - 1]
Nếu K[Mid] = X thì tìm kiếm thành công (kết thúcquá 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ìmkiếm là rỗng tức là L > R
1.3.2 Nội dung chương trình
* Code của ngôn ngữ lập trình PASCAL
Function TK_NhiPhan(X: Key): integer;
Trang 4exit(0); {không tìm thấ% y x thì tra & ra kế% t qua & bằng 0}
1.3.4 Mở rộng phương pháp tìm kiếm nhị phân
Trong các bài toán Tin học, có những bài toán không chỉ đơnthuần tìm vị trí của khóa X trong một dãy đối tượng được sắpxếp mà có thể là tìm phần tử có khóa nhỏ nhất lớn hơn X (hoặc
Trang 5tìm phần tử có khóa lớn nhất nhỏ hơn X) Khi đó vẫn sử dụngtìm kiếm nhị phân nhưng cần cải tiến một chút trong hàm tìmkiếm này.
Ví dụ: dùng tìm kiếm nhị phân để tìm phần tử có giá trị nhỏnhất lớn hơn X trong dãy phần tử đã sắp xếp tăng dần
* Code của ngôn ngữ lập trình PASCAL
function tk_NhiPhan(x: integer): integer;
Trang 62 BÀI TẬP ÁP DỤNG
Bài 1 Dãy con
Cho một dãy số nguyên dương a1, a2, , aN (10 < N < 100.000), ai
≤ 10.000 với mọi i=1 N và một số nguyên dương S (S <
100.000.000)
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
Bài toán này có thể giải theo 2 cách sau:
Cách 1: dễ dàng giải bài toán với 1 cách làm trâu bò 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 đồngthờ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(N2)
Trang 7Cách 2: Sử dụng phương pháp tìm kiếm nhị phân để giải bài
toán:
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 => 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:
Bài 2: Đếm tam giác
Cho 3 dãy số dương A, B, C cùng có N phần tử Hãy đếm xem cóbao nhiêu bộ 3 số A[i], B[j] và C[k] mà 3 số này là 3 cạnh của 1tam giác
Dữ liệu vào: từ file TRIANGLE.INP với cấu trúc:
- Dòng đầu chứa số nguyên n (n <= 1000)
Trang 8- Dòng thứ hai chứa các số A1, A2, , An.
Chúng ta có thể giải bài này bằng 2 cách như sau:
Cách 1: Bài toán được giải một cách dễ dàng bằng phương pháp
Trang 9- Trước hết ta giải bài toán phụ như sau: Cho dãy không giảm A,
và hai số x < y Hãy sử dụng phương pháp tìm kiếm nhị phân đểđếm xem có bao nhiêu số A[i] thỏa mã x < A[i] < y
Bước 2 Sử dụng 2 vòn g lặp lồng nhau duyệt mảng A và B
- Nếu |ai-bj| < c[N] thì xét tiếp
o Nếu ai+bj > c1 thì
Trang 10 Tìm kiếm số |ai – bj| trong dãy c bằng phươngpháp tìm kiếm nhị phân được vị trí l
Tìm kiếm số ai+bj trong dãy c bằng phương pháptìm kiếm nhị phân được vị trí k
Nếu k >= l thi dem = dem + k – l + 1;
Bài 3 Trò chơi với dãy số
Hai bạn học sinh trong lúc nhàn rỗi nghĩ ra trò chơi sau đây Mỗibạn chọn trước một dãy số gồm n số nguyên Giả sử dãy số mà bạn
thứ nhất chọn là: b 1 , b 2 , , b n còn dãy số mà bạn thứ hai chọn là c 1 ,
c 2 , , c n
Mỗi lượt chơi mỗi bạn đưa ra một số hạng trong dãy số của mình.Nếu bạn thứ nhất đưa ra số hạng bi (1 <= i <= n), còn bạn thứ haiđưa ra số hạng cj (1 <= j <= n) thì giá của lượt chơi đó sẽ là |bi+cj|
Ví dụ: Giả sử dãy số bạn thứ nhất chọn là 1, -2; còn dãy số mà bạnthứ hai chọn là 2, 3 Khi đó các khả năng có thể của một lượt chơi
là (1, 2), (1, 3), (-2, 2), (-2, 3) Như vậy, giá nhỏ nhất của một lượtchơi trong số các lượt chơi có thể là 0 tương ứng với giá của lượtchơi (-2, 2)
Yêu cầu: Hãy xác định giá nhỏ nhất của một lượt chơi trong số các
lượt chơi có thể
INPUT: vào từ file văn bản SEQGAME.INP
- Dòng đầu là số nguyên dương (1 <= n <= 105)
Trang 11- Dòng thứ hai chứa các số là dãy b (|bi| <= 109)
- Dòng thứ hai chứa các số là dãy c (|ci| <= 109)
OUTPUT: ghi ra file văn bản SEQGAME.OUT giá trị nhỏ nhất
Cách 2: Sử dụng phương pháp tìm kiếm nhị phân như sau:
Bước 1: Sắp xếp dãy A tăng dần
Bước 2: xét các giá trị B[i]
Xét các giá trị A[g] (g = (d + c) div 2 với d = 1, c = N)
Min := A[g] + B[i]
- Nếu A[g] + B[i] < 0 thì phải tăng g lên để tổng gần 0 hơn khi
đó d := g + 1
Trang 12- Nếu A[g] + B[j] > 0 thì phải giảm g xuống để tổng gần 0 hơnkhi đó c := g – 1.
- Nếu Min = 0 thì thoát
n sản phẩm đánh số từ 1 đến n theo đúng thứ tự mà chúng rời khỏidây chuyền Sản phẩm thứ i có trọng lượng là ai, i = 1, 2, …, n.Ban Giám đốc nhà máy qui định rằng sản phẩm xuất xưởng củamỗi ca làm việc phải được xếp vào trong không quá k hộp
Yêu cầu: Hãy giúp người quản đốc của ca làm việc xác định giátrị M nhỏ nhất sao cho số hộp mà máy tự động cần sử dụng để xếpdãy n sản phẩm xuất xưởng của ca không vượt quá số k cho trước
Dữ liệu: Vào từ file văn bản ZXY.INP:
Trang 13• Dòng đầu tiên chứa hai số nguyên n và k, (1 <= k <= n <=15000);
• Dòng thứ i trong n dòng tiếp theo chứa số nguyên dương ai (ai
<= 30000), i =1, 2, …, n
Các số trên một dòng cách nhau ít nhất một dấu cách
Kết quả: Ghi ra file ZXY.OUT một số nguyên duy nhất là dunglượng của hộp
Trang 14- Dem = so lượng hộp trọng lượng M có thể chứa được n vậtphẩm
- Nếu dem > k nghĩa là M quá nhỏ vì vậy cần tăng kích thướccủa M bằng cách chặt nhị phân tìm M trong đoạn từ d = M +
Bài 5: Robot cứu hỏa (Nguồn bài: Đề thi HSG QG 2007)
Trên một mạng lưới giao thông có n nút, các nút được đánh số từ 1đến n và giữa hai nút bất kỳ có không quá một đường nối trực tiếp(đường nối trực tiếp là một đường hai chiều) Ta gọi đường đi từnút s đến nút t là một dãy các nút và các đường nối trực tiếp códạng:
s = u1, e1, u2, , ui, ei, ui+1, , uk-1, ek-1, uk = t,trong đó u1, u2, …, uk là các nút trong mạng lưới giao thông, ei làđường nối trực tiếp giữa nút ui và ui+1 (không có nút uj nào xuấthiện nhiều hơn một lần trong dãy trên, j = 1, 2, …, k)
Biết rằng mạng lưới giao thông được xét luôn có ít nhất một đường
đi từ nút 1 đến nút n
Một robot chứa đầy bình với w đơn vị năng lượng, cần đi từ trạmcứu hoả đặt tại nút 1 đến nơi xảy ra hoả hoạn ở nút n, trong thời
Trang 15gian ít nhất có thể Thời gian và chi phí năng lượng để robot đi trênđường nối trực tiếp từ nút i đến nút j tương ứng là tij và cij (1 <= i, j
<= n) Robot chỉ có thể đi được trên đường nối trực tiếp từ nút iđến nút j nếu năng lượng còn lại trong bình chứa không ít hơn cij (1
<= i, j <= n) Nếu robot đi đến một nút có trạm tiếp năng lượng(một nút có thể có hoặc không có trạm tiếp năng lượng) thì nó tựđộng được nạp đầy năng lượng vào bình chứa với thời gian nạp coinhư không đáng kể
Yêu cầu: Hãy xác định giá trị w nhỏ nhất để robot đi được trên
một đường đi từ nút 1 đến nút n trong thời gian ít nhất
Input: Đọc từ file QBROBOT.INP:
Dòng đầu tiên chứa một số nguyên dương n (2 <= n <= 500);
Dòng thứ hai chứa n số, trong đó số thứ j bằng 1 hoặc 0 tươngứng ở nút j có hoặc không có trạm tiếp năng lượng (j = 1, 2,
Hai số liên tiếp trên một dòng trong file dữ liệu cách nhau ít nhất một dấu cách.
Trang 16Output: Ghi ra file QBROBOT.OUT: Ghi ra số nguyên dương w
Trước hết ta nhận thấy rằng thời gian đi nhỏ nhất từ 1 -> N được
ưu tiên hàng đầu Vì vậy dùng Dijkstra để tìm đường đi ngắn nhất
từ 1 -> N, gọi d[i] là khoảng cách nhỏ nhất từ i -> N Sau đó sẽ tìmgiá trị w nhỏ nhất mà có thể đi với thời gian ngắn nhất vừa tìmđược là d[1]
Bài toán có thể giải quyết bằng phương pháp tìm kiếm nhị phânnhư sau:
Vì w chắc chắn nằm trong đoạn từ 1 -> + nên: d := 1 và c :=100000000;
Trang 17o Ngược lại: w đã thoản mãn có thể đi từ 1 -> N với thờigian ngắn nhất Tuy nhiên w chưa chắc là nhỏ nhất Vìvậy cần giảm giá trị w bằng cách chặt nhị phân trongđoạn từ d -> c = w – 1
- Vấn đề cần giải quyết bây giờ là trong thủ tục DFS(1) thì điềukiện để đi từ đỉnh u -> v là gì?
- Câu hỏi trên sẽ được giải đáp nếu trả lời được 3 câu hỏi sau:
o Từ u -> v có đường đi trực tiếp không? nếu có đường đitrực tiếp thì trả lời câu hỏi tiếp
o Đỉnh u có trạm tiếp năng lượng không? hoặc năng lượngcòn lại của robot có thể đi từ u -> v không Nếu thỏamãn thì trả lời câu hỏi tiếp:
o Đường đi từ u -> v có đảm bảo là nằm trên một đường
đi từ 1 -> N với thời gian ngắn nhất không? tức là tổngthời gian từ 1 –> u với t(u,v) và d[v] có bằng d[1]
Trang 18Bài 6 Chiều cao xe
Đất nước Alpha có N thành phố và M cây cầu hai chiều nối
trực tiếp một số thành phố, các cặp thành phố hoặc có đường đitrực tiếp, hoặc có đường đi qua các đỉnh trung gian Tại mỗi câycầu có ghi giới hạn độ cao tối đa của xe khi chạy qua nó
Thủ đô của đất nước Alpha được đặt tại thành phố s, đất nước
có một thành phố t là khu khai thác tài nguyên khoáng sản vô cùng
lớn Tài nguyên khoáng sản sau khi được khai thác sẽ chuyển lêncác xe ô tô tải và chở về thủ đô Để có thể khai thác triệt để nguồntài nguyên, người ta phải dùng các xe ô tô có công ten nơ (biết các
xe đủ khỏe để có thể chịu được trọng tải của công ten nơ), tuynhiên khi qua các cầu thì lại bị giới hạn về chiều cao, vì vậy cầnthiết kế sao cho chiều cao của xe khi chở các công ten nơ là caonhất để các xe có thể chở nguồn tài nguyên về thủ đô
Yêu cầu: Hãy tìm chiều cao lớn nhất của xe khi chở các công
ten nơ
Input: Đọc từ file height.inp:
- Dòng đầu tiên là hai số N, M, s, t (2 <= N <= 104, 1 <= M <=
Trang 19- Dòng đầu tiên là chiều cao lớn nhất tìm được.
- Dòng thứ 2 đường đi ngắn nhất từ đỉnh s đến t với chiều cao vừatìm được
4
3
5 7
3
6 4
1
5
Trang 20kq = Mid;
R = Mid – 1;
} ngược lại thì L = Mid + 1;
Trong đó hàm check(Mid) dùng để kiểm tra xem liệu với chiềucao Mid thì xe có thể đi từ s đến t không? (có thể dùng thuậttoán DFS(s) hoặc BFS(s) để kiểm tra điều này)
Nếu check(Mid) = true thì hi vọng tìm được giá trị Mid nhỏ hơnnữa bằng cách giảm giá trị R = Mid – 1
Nếu check(Mid) = false thì giá trị Mid là quá nhỏ nên phải tănggiá trị này lên bằng cách thay đổi giá trị L = Mid + 1
3 Kết luận
Nhìn chung các bài toán được ứng dụng phương pháp tìm kiếm nhịphân thường đi cặp với thuật toán sắp xếp, và hầu như các bài toánđều là những bài toán ở mức độ không khó về mặt giải thuật Tuynhiên nó lại được đưa vào nhiều đề thi HSG các cấp, và nếu nhưhọc sinh được làm quen nhiều với các dạng bài toán này thì việcnhận dạng và giải chúng là điều mà các em có thể làm được rất tốt.Trong bài viết của tôi có lẽ còn sơ sài, nhiều thiếu sót, rất mongđược sự đóng góp của các đồng nghiệp để chuyên đề được hay hơn
và hoàn thiện hơn
Trang 21Xin trân trọng cảm ơn!