Chuyên đề bồi dưỡng học sinh giỏi: Cấu trúc dữ liệu heap và ứng dụng
Trang 1MỤC LỤC
A Phần mở đầu 1
I Lý do chọn đề tài 1
II Mục đích của đề tài 1
III Nhiệm vụ và phương pháp nghiên cứu 1
VI Điểm mới trong kết quả nghiên cứu 1
MỤC LỤC 1
Khái niệm 3
Các thao tác thường dùng đối với Heap Max 3
Khai báo 3
UpHeap 4
DownHeap 4
Push 6
Pop 6
Dijkstra Heap 6
Một số bài tập ứng dụng 8
1.Bài tập 1: Thả xốp 8
2 Bài tập 2: PILOT 10
3 Bài tập 3: Tiểu thuyết trinh thám 13
4.Bài tập 4: BASE3 17
Tài liệu tham khảo 21
Trang 2A PHẦN MỞ ĐẦU
I LÝ DO CHỌN ĐỀ TÀI
Công tác bồi dưỡng học sinh giỏi (HSG) là một công tác mũi nhọn trong việc nâng cao chất lượng giáo dục, tạo nguồn lực, bồi dưỡng nhân tài cho nhà trường nói riêng, cho địa phương nói chung Bồi dưỡng HSG là một công việc khó khăn và lâu dài, đòi hỏi nhiều công sức của thầy và trò.
Trong quá trình bồi dưỡng HSG môn Tin học ở bậc THPT thì cấu trúc dữ liệu heap
là cấu trúc dữ liệu đặc biệt quan trọng Từ lí do trên, tôi xin trình bày sáng kiến kinh nghiệm “CHUYÊN ĐỀ BỒI DƯỠNG HSG : CẤU TRÚC DỮ LIỆU HEAP VÀ ỨNG DỤNG”, để học sinh dễ dàng tiếp thu kiến thức mới.
Do lần đầu tiên thực hiện làm sáng kiến kinh nghiệm, nên không tránh khỏi những thiếu sót Mong quý thầy cô góp ý để lần sau làm tốt hơn.
II MỤC ĐÍCH CỦA ĐỀ TÀI
Heap là một trong những cấu trúc dữ liệu đặc biệt quan trọng, nó giúp ta có thể giải được nhiều bài toán trong thời gian cho phép Độ phức tạp thông thường khi làm việc với
Heap là O(logN) Khi được học chuyên đề này học sinh sẽ lập trình thành thạo với các bài
toán ứng dụng của heap.
III NHIỆM VỤ VÀ PHƯƠNG PHÁP NGHIÊN CỨU
Viết sáng kiến kinh nghiệm thường xuyên liên tục cũng là nhiệm vụ chính trị của mỗi giáo viên, nhưng cần phải lựa chọn phương pháp nghiên cứu đúng đắn và phù hợp với nhà trường trung học phổ thông Sáng kiến kinh nghiệm đang trình bày của tôi dựa theo các luận cứ khoa học hướng đối tượng, cụ thể: thuyết trình, quan sát, điều tra cơ bản, phân tích kết quả thực nghiệm sư phạm,v.v… phù hợp với bài học và môn học thuộc lĩnh vực cấu trúc dữ liệu.
IV ĐIỂM MỚI TRONG KẾT QUẢ NGHIÊN CỨU
Giúp học sinh hiểu rõ về cấu trúc dữ liệu heap và sử dụng thành thạo trong lập trình Ngoài ra, tôi mạnh dạn trình bày sáng kiến kinh nghiệm này còn để phục vụ cho những năm dạy tiếp theo
Trang 3B PHẦN NỘI DUNG Cấu trúc dữ liệu HEAP
Khái niệm
Heap là một trong những cấu trúc dữ liệu đặc biệt quan trọng, nó giúp ta có thể giải được nhiều bài toán trong thời gian cho phép Độ phức tạp thông thường khi làm việc với
Heap là O(logN).
Heap thực chất là một cây cân bằng thỏa mãn các điều kiện sau:
• Một nút có không quá 2 nút con.
• Với Heap Max thì nút gốc là nút lớn nhất, mọi nút con đều không lớn hơn nút cha của nó Với Heap Min thì ngược lại
Mặc dù được mô tả như cây nhưng Heap có thể được biểu diễn bằng mảng Nút con của nút i là 2*i và 2*i+1 Do Heap là cây cân bằng nên độ cao của 1 nút luôn <= logN Ứng dụng chủ yếu của Heap là tìm Min, Max trong 1 tập hợp động (có thể thay đổi, thêm, bớt các phần tử) nhưng như vậy đã là quá đủ.
(Mô hình biểu diễn Heap bằng cây nhị phân và bằng mảng)
Các thao tác thường dùng đối với Heap Max
Khai báo
Ở ví dụ này, Heap sẽ là mảng một chiều kiểu LongInt, nHeap là số phần tử của mảng.
Trang 4Nếu 1 nút lớn hơn nút cha của nó thì di chuyển nó lên trên:
Procedure UpHeap(i : LongInt);
Begin
if (i = 1) or (Heap[i] < Heap[i div 2]) then exit; // Nếu i là nút gốc hoặc
nhỏ hơn nút cha thì không làm việc
swap(Heap[i] , Heap[i div 2]); // Đổi chỗ 2 phần tử trong Heap;
UpHeap(i div 2); // Tiếp tục di chuyển lên trên
end;
DownHeap
Nếu 1 nút nhỏ hơn nút con thì đẩy nó xuống dưới:
Trang 5Procedure DownHeap(i : LongInt);
Var
j : LongInt;
Begin
j := i*2;
if j > nHeap then exit; // Nếu i không có nút con thì không làm việc
if (j < nHeap) and (Heap[j] < Heap[j+1]) then Inc(j); // Nếu i có 2 nút con thì
chọn nút ưu tiên hơn
if Heap[i] < Heap[j] then // Nếu nút cha nhỏ hơn nút con
Trang 6Inc(nHeap); // Tăng số phần tử của Heap
Heap[nHeap] := x; // Thêm x vào Heap
Pop := Heap[v]; // Lấy phần tử ở vị trí v ra khỏi Heap
Heap[v] := Heap[nHeap]; // Đưa phần tử ở cuối Heap vào vị trí v
Dec(nHeap); // Giảm số phần tử của Heap đi 1
{Chỉnh lại Heap}
UpHeap(v);
DownHeap(v);
End;
Ngoài ra, khi sử dụng thuật toán Dijkstra/Prim kết hợp cấu trúc Heap, bạn còn
có thể sử dụng cách Push và Pop khác thuận lợi hơn so với cách trình bày ở trên:
child := pos[v]; // child là vị trí của đỉnh v trong Heap
if child = 0 then // Nếu đỉnh v chưa có trong Heap
Trang 7begin
Inc(nHeap); // Tăng số phần tử của Heap
child := nHeap; // Đưa v vào cuối Heap
end;
parent := child div 2; // parent là nút cha của child
while (parent > 0) and (d[Heap[parent]] > d[v]) do // Nếu đỉnh ở nút parent kém ưu tiên hơn v thì bị “kéo xuống” nút child
begin
Heap[child] := Heap[parent]; // Đẩy đỉnh được lưu trong nút cha xuống nút con pos[Heap[child]] := child; // Ghi nhận lại vị trí mới của đỉnh đó
child := parent; // Tiếp tục di chuyển lên
parent := child div 2;
v := Heap[nHeap]; // v là đỉnh ở nút lá cuối Heap, sẽ được đảo lên đầu và vun đống
Dec(nHeap); // Giảm số phần tử của Heap
pos[Heap[r]] := r; // Cập nhật lại vị trí mới trong Heap của đỉnh đó
r := c; // Tiếp tục di chuyển xuống dưới
end;
Heap[r] := v; // Đỉnh v được đặt vào vị trí r để đảm bảo cấu trúc Heap
pos[v] := r; // Ghi nhận vị trí mới của đỉnh v trong Heap
end;
Trang 8Một số bài tập ứng dụng
1 Bài tập 1: Thả xốp
Có N hạt xốp, hạt thứ i có khối lượng , được thả lần lượt xuống một ống nước đặc biệt được thiết kế sao cho tại mỗi thời điểm chỉ có một hạt xốp nhẹ nhất nổi lên trên bề mặt Trước mỗi lần thả, hạt xốp đang nổi trên bề mặt sẽ bị ngấm nước và tăng gấp đôi khối lượng Hỏi sau khi thả hạt xốp cuối cùng vào ống thì khối lượng xốp tăng so với tổng khối lượng ban đầu là bao nhiêu ?
Dữ liệu: Vào từ file văn bản SPONGE.INP
• Dòng 1: Số nguyên dương N
• Dòng 2: N số nguyên dương
Kết quả: Ghi ra file văn bản SPONGE.OUT
• Ghi 1 số duy nhất là đáp án của bài toán
Trang 9If (heap[j] > heap[j+1]) and (j <nheap) then inc(j);
If heap[i] > heap[j] then
Trang 10HT airline có tất cả N phi công (N là số chẵn), các phi công được đánh số từ 1 đến N (Phi công 1 là phi công trẻ nhất, phi công i là phi công có tuổi cao thứ i,… phi công n là
phi công cao tuổi nhất) HT airline cần chính xác
2
N
phi hành đoàn, mỗi phi hành đoàn
gồm 2 phi công (một lái chính và một lái phụ), lái chính phải nhiều tuổi hơn lái phụ.
Hợp đồng mà công ty kí với các phi công có 2 điều khoản rõ ràng: tiền lương khi là lái chính và tiền lương khi là lái phụ Rõ ràng, đối với 1 phi công, tiền lương lái chính bao giờ cũng cao hơn tiền lương khi lái phụ Tuy nhiên, với một phi hành đoàn, có thể tiền lương của lái chính lại thấp hơn lái phụ.
Để giảm chi phí trả tiền lương, HT phải xác định một cách phân chia tối ưu
2
N
phi hành đoàn.
Bạn hãy giúp HT viết chương trình xác định số tiền tối thiểu để trả lương cho N phi công.
Dữ liệu : Vào từ file văn bản PILOT.INP
• Dòng 1 : Số nguyên dương N, là số phi công ở HT airline.
• N dòng tiếp theo, dòng thứ i là thông tin về phi công i : gồm hai số a và c viết cách nhau 1 dấu cách trống, tương ứng là tiền lương khi lái chính và tiền lương khi lái phụ.
Kết quả: Dữ liệu ra ghi vào file PILOT.OUT
Một số nguyên duy nhất là tiền lương tối thiểu phải trả cho N phi công.
Hạn chế :
2 ≤ N ≤ 10000; N là số chẵn.
Trang 12if (i = 1) or (h[i] < h[i div 2]) then exit;
if h[i div 2] < h[i] then
Trang 133 Bài tập 3: Tiểu thuyết trinh thám
Ivan Đneprôp viết truyện tiểu thuyết trinh thám Truyện của anh ta không có gì đặc sắc: không có các tình huống ly kỳ đặc biệt, cũng không có các chi tiết hài hước tế nhị Thậm chí một hiệu sách đã bán các sáng tác của Ivan theo cân! Nhưng độc giả lại thích truyện của Ivan Nó dễ hiểu và giúp người ta thư giản sau một ngày lao động mệt nhọc Thực ra, bí mật sự thành công của Ivan là ở chổ không phải chính anh nghĩ ra các tình huống mà là người em trai Alexei Ivan có nhiệm vụ viết nó thành các bestsellers Dĩ nhiên hai anh em chia nhau hợp lý số tiền kiếm được Điều đáng tiếc là khả năng sáng tạo các tình huống ly kỳ của Alexei lại phụ thuộc vào chu kỳ sinh học của anh Hai anh em phân tích bảng chu kỳ sinh học của Alexei và thấy rằng trong thời gian tới Alexei sẽ nghĩ
được n chủ đề mới, chủ đề thứ i sẽ được nghĩ ra ở ngày ri Trong cùng một ngày có thể Alexei nghĩ ra tới vài câu chuyện.
Với mỗi chủ đề, Ivan thời lượng cần thiết để hoàn thành tác phẩm và tính được rằng
chủ đề thứ i cần có pi ngày để viết Ivan có trí nhớ cực tốt, vì vậy anh có thể tạm bỏ dở một truyện, chuyển sang viết truyện khác sau đó quay lại hoàn thành nốt các truyện dở dang.
Dĩ nhiên, hai anh em muốn sách được viết càng nhanh càng tốt, tức là phải cực tiểu hóa thời gian trung bình từ thời điểm hiện tại tới thời điểm lúc tiểu thuyết hoàn thành Vì
số sách là cố định, nên điều này tương đương với việc cực tiểu hóa tổng thời gian viết tất
cả các cuốn sách Điều này có nghĩa là nếu cuốn sách thứ i được hoàn thành vào ngày ci
thì ∑ci phải được cực tiểu hóa Ví dụ, ở ngày thứ nhất Alexei nghĩ ra một cốt chuyện mà Ivan cần viết trong 5 ngày, Ivan bắt tay viết ngay Ngày thứ 2 Alexei nghĩ thêm một cót chuyện mới cần viết trong một ngày Ivan chuyển sang viết chuyện mới, ngày thứ 3:
Trang 14chuện thứ hai hoàn thành và Ivan quay lại viết tiếp chuyện thứ nhất, mất thêm 4 ngày nữa, đến ngày thứ 7 chuyện thứ nhất hoàn thành Tổng các thời điểm hoàn thành là 3+7 = 10.
Yêu cầu: Cho n, ri và pi Hãy xác định tổng thời gian ngắn nhất hoàn thành tất cả các truyện.
Dữ liệu: Vào từ file văn bản PULP.INP:
• Dòng 1: Chứa số nguyên n (1 ≤ n ≤ 100.000),
• Mỗi dòng trong n dòng sau chứa 2 số nguyên ri và pi.
Kết quả: Ghi ra file PULP.OUT
• Một số nguyên – tổng thời gian ngắn nhất tìm được.
1 Sort tăng theo R[i]
2 Ví dụ với các thời điểm , dễ dàng ta thấy
3 Với mỗi khoảng thời gian t = R[i] – R[i-1], ta ưu tiên giải quyết công việc cần ít thời
gian nhất, giả sử là công việc P (Thấy ngay là sử dụng Heap để lấy công việc có thời gian nhỏ nhất)
a Nếu thời gian thực hiện công việc P < t thì thực hiện hết công việc P, thời gian còn lại thực hiện tiếp các công việc có thời gian nhỏ tiếp theo.
b Nếu thời gian thực hiện công việc P > t thì chúng ta thực hiện công việc P trong khoảng thời gian t, thời gian còn lại là t[P] – t ta lưu lại trong Heap để tính tiếp.
4 Sau khi xét đến thời điểm N, lúc này ta sẽ phải làm tất cả các công việc còn lại tuần
tự từ nhỏ đến lớn, hay là lấy tất cả các phần tử trong Heap ra là xong.
Trang 15if (i = 1) or (h[i] > h[i div 2]) then exit;
if h[i div 2] > h[i] then
Trang 17Cho 3 số ở hệ cơ số 3 (viết bởi 3 số 0, 1, 2) Hãy tìm một chữ số N ở hệ cơ số 3 sao cho N
có một số lẻ chữ số và số 1 nằm ở chính giữa số N Số N phải thu được từ việc liên kết 3
số cho trước, mỗi số trong 3 số có thể được sử dụng 0 hoặc nhiều lần:
020 2020
Trang 18Ký tự 1 ở giữa của xâu kết quả phải thuộc 1 trong 3 xâu:
Giả sử ký tự 1 của kết quả nằm ở vị trí I của xâu , ta sẽ xây dựng xâu kết quả bằng cách thêm từng xâu vào trái hoặc phải (phần L là trái, ký tự 1 ở giữa, phần R là phải)
Ta sẽ xây dựng xâu đến khi thì dừng lại (yêu cầu đề bài)
Dễ thấy, ta chỉ quan tâm tới ghi nhận kết quả Tức là nếu tồn tại cách xây dựng L’, R’ mà
thỏa mãn cũng sử dụng cách xây dựng đó được với các cặp với , chỉ cần lưu 1 cặp có
Quy hoạch động = cách xếp có với
Nếu mỗi lần ta luôn nắp xâu vào nửa ngắn hơn thì luôn đảm bảo
thái + độ dài xâu nắp thêm vào Bài toán trở thành Dijkstra Heap
về trạng thái Các trạng thái cơ sở có thể là các ký tự 1 của 1 trong 3 xâu ban đầu Đáp án bài toán là
Trang 19h[i] := h[i div 2] ;
h2[i] := h2[i div 2];
if d[x,y] <= d[h[j],h2[j]] then break ;
Trang 21thể giải được nhiều bài toán trong thời gian cho phép Độ phức tạp thông thường khi làm
việc với Heap là O(lgN) Học sinh hiểu được bản chất của cấu trúc dữ liệu heap sẽ giúp
cho học sinh yêu thích môn học và ham học hỏi, tìm tòi, sáng tạo.
Đề tài này đã mang tính thực tiễn rất cao, cụ thể là: đây là kiến thức rất quan trọng trong quá trình bồi dưỡng học sinh giỏi.
Kết quả là có rất nhiều học sinh đã làm được các bài tập có ứng dụng của heap.
Tài liệu tham khảo
1 Giải thuật và lập trình – T.S Lê Minh Hoàng – ĐHSP Hà Nội
2 Website: www.infoarena.ro
XÁC NHẬN CỦA THỦ
TRƯỞNG ĐƠN VỊ
Thanh Hóa, ngày 19 tháng 5 năm 2013
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.
(Ký và ghi rõ họ tên)
Nguyễn Đặng Phú