Công nghệ thông tin là một ngành khoa học đang phát triển mạnh mẽ và có nhiều ứng dụng trong tất cả các hoạt động của xã hội, trong vài chục năm trở lại đây công nghệ thông tin đã thâm nhập vào mọi lĩnh vực hoạt động của con người, sự phát triển của công nghệ thông tin đang dẫn đến những thay đổi quan trọng trong cách sống và ngay cả cách suy nghĩ của chúng ta, ngoài sự tò mò, ham hiểu biết mỗi người phải ý thức rằng nếu không có hiểu biết nhất định về máy tính nói riêng và tin học nói chung thì khó có thể hòa nhập vào cuộc sống hiện đại. Vì vậy việc đưa tin học vào giảng dạy trong các trường phổ thông là việc làm rất cần thiết, giúp các em nắm được các kiến thức cơ bản, những lợi ích của tin học để áp dụng vào đời sống và góp phần làm nền tảng kiến thức để học tập cao hơn. Từ thực tế giảng dạy của bản thân tôi nhận thấy việc nắm vững các thuật toán và áp dụng nó một cách linh hoạt trong các bài tập nhất định là không đơn giản, để có thể nhận dạng một bài toán có thể thực hiện với các thuật toán không phải dễ, ngoài ra để cài đặt được thuật toán hiệu quả nhất cũng đòi hỏi người lập trình nắm vững các phương pháp thiết kế thuật toán; đa số học sinh cảm thấy khó khăn sợ khi giải các bài toán tin có liên quan đến thuật toán nâng cao, rất lúng túng trong quá trình phân tích, tổ chức dữ liệu, tìm ra thuật toán hiệu quả; trước hết là thực hiện đổi mới phương pháp giảng dạy Tin học làm cho học sinh tìm ra những kết quả sáng tạo, lời giải hay trên các bài toán, giúp bản thân nắm vững hơn nữa về tư duy thuật toán, khả năng lập trình. Xuất phát từ những lí do trên, tôi xin trình bày một sáng kiến nhỏ trong công tác giảng dạy với đề tài: “SỬ DỤNG THUẬT TOÁN ĐẾM PHÂN PHỐI VÀ THUẬT TOÁN SẮP XẾP NHANH (QUICH SORT) ĐỂ GIẢI MỘT SỐ BÀI TOÁN TIN HỌC’’.
Trang 1I ĐẶT VẤN ĐỀ:
Công nghệ thông tin là một ngành khoa học đang phát triển mạnh mẽ và
có nhiều ứng dụng trong tất cả các hoạt động của xã hội, trong vài chục năm trởlại đây công nghệ thông tin đã thâm nhập vào mọi lĩnh vực hoạt động của conngười, sự phát triển của công nghệ thông tin đang dẫn đến những thay đổi quantrọng trong cách sống và ngay cả cách suy nghĩ của chúng ta, ngoài sự tò mò,ham hiểu biết mỗi người phải ý thức rằng nếu không có hiểu biết nhất định vềmáy tính nói riêng và tin học nói chung thì khó có thể hòa nhập vào cuộc sốnghiện đại
Vì vậy việc đưa tin học vào giảng dạy trong các trường phổ thông là việclàm rất cần thiết, giúp các em nắm được các kiến thức cơ bản, những lợi ích củatin học để áp dụng vào đời sống và góp phần làm nền tảng kiến thức để học tậpcao hơn
Từ thực tế giảng dạy của bản thân tôi nhận thấy việc nắm vững các thuậttoán và áp dụng nó một cách linh hoạt trong các bài tập nhất định là không đơngiản, để có thể nhận dạng một bài toán có thể thực hiện với các thuật toánkhông phải dễ, ngoài ra để cài đặt được thuật toán hiệu quả nhất cũng đòi hỏingười lập trình nắm vững các phương pháp thiết kế thuật toán; đa số học sinhcảm thấy khó khăn sợ khi giải các bài toán tin có liên quan đến thuật toán nângcao, rất lúng túng trong quá trình phân tích, tổ chức dữ liệu, tìm ra thuật toánhiệu quả; trước hết là thực hiện đổi mới phương pháp giảng dạy Tin học làm chohọc sinh tìm ra những kết quả sáng tạo, lời giải hay trên các bài toán, giúp bảnthân nắm vững hơn nữa về tư duy thuật toán, khả năng lập trình
Xuất phát từ những lí do trên, tôi xin trình bày một sáng kiến nhỏ trong
công tác giảng dạy với đề tài: “SỬ DỤNG THUẬT TOÁN ĐẾM PHÂN PHỐI VÀ THUẬT TOÁN SẮP XẾP NHANH (QUICH SORT) ĐỂ GIẢI MỘT SỐ BÀI TOÁN TIN HỌC’’
Trang 2II GIẢI QUYẾT VẤN ĐỀ:
Đề tài: “SỬ DỤNG THUẬT TOÁN ĐẾM PHÂN PHỐI VÀ THUẬT
TOÁN SẮP XẾP NHANH (QUICH SORT) ĐỂ GIẢI MỘT SỐ BÀI TOÁN TIN HỌC’’
1 CƠ SỞ LÝ LUẬN CỦA VẤN ĐỀ:
Trong quá trình giảng dạy trên lớp và trong quá trình bồi dưỡng học sinhgiỏi tin học 10, 11, 12 mà tôi đã dạy trong nhiều năm qua, tôi thấy các em họcsinh khi gặp những bài toán yêu cầu ta phải sử dụng đến các thuật toán nâng cao
để giải như: Các thuật toán: Đếm, sắp xếp, tìm kiếm, quy hoạch động, đồ thị …Tôi nhận thấy việc nắm vững các thuật toán và áp dụng nó một cách linh hoạttrong các bài tập nhất định là không đơn giản, đa số học sinh cảm thấy khó khăn
sợ khi giải các bài toán có liên quan đến thuật toán nâng cao; rất lúng túng trongquá trình phân tích, tổ chức dữ liệu, tìm ra thuật toán hiệu quả; trước hết là thựchiện đổi mới phương pháp giảng dạy Tin học làm cho học sinh tìm ra những kếtquả sáng tạo, lời giải hay trên các bài toán; giúp bản thân nắm vững hơn nữa về
tư duy thuật toán, khả năng lập trình, tôi đã chọn đề tài: “SỬ DỤNG THUẬT TOÁN ĐẾM PHÂN PHỐI VÀ THUẬT TOÁN SẮP XẾP NHANH (QUICH SORT) ĐỂ GIẢI MỘT SỐ BÀI TOÁN TIN HỌC’’
3 CÁC BIỆN PHÁP ĐÃ TIẾN HÀNH ĐÊ GIẢI QUYẾT VẤN ĐỀ:
Trong ngôn ngữ lập trình, các bài toán có liên quan đến đếm các đối tượng rất dễ xây dựng thuật toán cho nó; tuy nhiên, khi gặp những bài toán đó thường yêu cầu với dữ liệu lớn; nếu không xây dựng được thuật toán tối ưu thì khó có thể đưa ra lời giải tốt; để tiếp cận và xử lý các bài toán đếm và sắp xếp
Trang 3một cách nhanh và hiệu quả là sử dụng thuật toán Đếm phân phối và thuật toán sắp xếp nhanh (Quick sort).
Thuật toán 1: Thuật toán đếm phân phối
Tư tưởng của thuật toán được xây dựng dựa trên suy nghĩ thực tế là để đếm số lượng bò trên một vùng xác định thì người ta phải tìm cách lùa chúng vào các chuồng (để chúng khỏi chạy rông) cho dễ đếm Đương nhiên là những con bò cùng loại phải được lùa vào cùng một chuồng để dễ phân biệt hoặc lùa mỗi con vào một chuồng thì càng tốt Tương tự như vậy, muốn giải bài toán đếmcác đối tượng thì ta dùng một cấu trúc dữ liệu hợp lý (sử dụng cấu trúc mảng) với ý nghĩa giống như các “chuồng” để lưu các đối tượng, mỗi phần tử của mảng tương ứng với một chuồng Trên cơ sở đó ta dễ dàng thực hiện được mục đích của mình là thực hiện thao tác đếm
Để hiểu rõ hơn về thuật toán trong quá trình giảng dạy trên lớp và bồi dưỡng học sinh giỏi tôi đã đưa ra các bài toán sau:
Xuất phát từ bài toán: Bài toán đặt ra là giả sử trên cánh đồng rộng thả rất
nhiều bò (N con), mỗi con bò đeo một thẻ có số hiệu nguyên dương (là số tháng tuổi của nó) Tất nhiên, hai con bò cùng tháng tuổi thì đeo thẻ có số hiệu như nhau Làm thế nào để đếm được loại bò nào có nhiều nhất?
Bài toán này có thể phát biểu lại như sau:
+ Nhập từ bàn phím số nguyên dương N (0 < N < 500) và các phần tử củamảng một chiều A(N) có giá trị nguyên dương (0 < A[i] < 100)
+ Giá trị nào xuất hiện nhiều nhất trong A và xuất hiện bao nhiêu lần?+ Ví dụ: A(16) = {1,2,3,5,4,5,6,5,6,7,1,6,5,5,8,9} thì A(16) có số phần tử giá trị bằng 5 là nhiều nhất Số lượng phần tử này là 5
Để giải bài toán này người ta dùng thuật toán “đếm phân phối ”
Xây dựng thuật toán:
+ Bước 1: Đóng dãy chuồng bò và đánh số các chuồng bằng các số tự
nhiên liên tiếp từ 1 đến max (max là số tháng tuổi của con bò già nhất), ban đầu
Trang 4mọi chuồng đều chưa có bò ở trong.
+ Bước 2: Lùa bò vào chuồng có số hiệu bằng số thẻ của nó.
+ Bước 3: Duyệt dãy chuồng bò tìm chuồng có nhiều bò nhất.
Áp dụng thuật toán vào bài tập:
Bước 1: Giả sử con bò thứ i có tháng tuổi là A[i] (1 < i < n) Coi mảng
B(n) như dãy chuồng bò, B[x] là số lượng bò (có x tháng tuổi) trong chuồng
có số hiệu x, ban đầu các phần tử của mảng B(n) đều bằng 0
Bước 2: Con bò có tháng tuổi A[i] phải vào chuồng bò có số hiệu A[i].
Thêm 1 con bò vào chuồng A[i] tương ứng với lệnh Inc(B[A[i]])
Readln(A[i]);
End;
{Khởi tạo dãy chuồng bò ban đầu chưa có bò}
Fillchar (B, sizeof (B) ,0) ;
Trang 5{Thực hiện lùa bò vào chuồng}
For i := 1 to N do inc (B [A[i] ] );
Ta đóng dãy chuồng B, đánh số chuồng lần lượt từ 1,2….32000 ( ai là các
số nguyên dương, ai<32000), ban đầu các chuồng đều trống) Duyệt mảng A banđầu, phần tử ai sẽ được “nhốt” vào chuồng có số ai (tăng B[a[i]] lên một đơnvị) Đếm số chuồng khác trống đó chính là số phần tử khác nhau của dãy banđầu
Chương trình:
Trang 6var A:array[1 1000] of integer;
Readln(A[i]);
End;
{khởi tạo ban đầu chuồng bò chưa có bò}
Fillchar(C,sizeof(C),0);
{lùa bò vào chuồng}
for i:=1 to N do inc(C[a[i]]);
{ tìm ra số phần tử khác nhau }
Dem:=0;
for j:=0 to maxint do if c[j]<>0 then inc(Dem);
writeln(' co ',Dem,’ phan tu khac nhau’);
End
Bài toán 3 : Nhập vào số nguyên dương N (2<N<10000) và một dãy a1, a2,….ancác phần tử nguyên dương
Yêu cầu: Hãy sắp xếp dãy số đã cho thành dãy số không giảm
Dữ liệu: Vào từ file văn bản baitoan3.inp
Trang 7- Dòng 1 chứa số nguyên dương n (1 ≤ n ≤ 10000);
- n dòng sau, mỗi dòng chứa một số nguyên dương ai (1≤ ai < 32000)
Kết quả: Đưa dãy đã được sắp xếp ra file văn bản baitoan3.out (các số
được viết trên một dòng, mỗi số cách nhau một ký tự trắng)
Chương trình:
const fv=' baitoan3.inp';
fr=' baitoan3.out';
var a:array[1 10000]of integer;
b:array[1 32000] of integer;
i,j,n:integer;
f:text;
begin assign(f,fv);
{lua bo vao chuong}
for i:=1 to n do inc(b[a[i]]);
assign(f,fr);
Trang 8rewrite(f);
{dua ra day duoc sap xep}
for i:=1 to 32000 do for j:=1 to b[i] do write(f,i,' ');
close(f);
end
Bài toán 4: Đếm số
Sơn là một học sinh đam mê Tin học và rất ngưỡng mộ tác giả người Việt
đã viết ra trò chơi FlappyBird nổi tiếng thế giới Cậu ta muốn tìm hiểu về cáchviết trò chơi Ban đầu, cậu ta muốn viết một trò chơi đơn giản như sau: Mỗi mộtlần chơi, máy tính sẽ sinh ngẫu nhiên n số nguyên dương ra màn hình, nhiệm vụngười chơi phải đếm được số lượng các số chỉ xuất hiện một lần trong mộtkhoảng thời gian giới hạn Các mức độ của trò chơi tương ứng với giá trị n lớnhay nhỏ
Sơn đã dùng ngôn ngữ lập trình để đếm được một cách nhanh chóng Em
có làm được điều đó không? Hãy vận dụng kiến thức lập trình để đóng vai trò làngười chơi nhé
Yêu cầu: Cho trước n số nguyên dương, đếm số lượng các số chỉ xuất
hiện một lần
Dữ liệu: Vào từ file văn bản input.inp
Dòng 1 chứa số nguyên dương n (1 ≤ n ≤ 106);
n dòng sau, dòng thứ i chứa một số nguyên dương ai (1≤ ai <106)
Kết quả: Đưa ra file văn bản input.out gồm một số là số lượng các số chỉ
xuất hiện một lần
Ví dụ:
Trang 9Input.int Input.out 4
2 6 6 3
Trang 10Dữ liệu vào: Cho trong file văn bản baitoan5.inp, gồm:
+ Dòng đầu tiên ghi một số N (1<=n<=1000);
+ Trong N dòng tiếp theo, mỗi dòng ghi 1 số nguyên dương
Dữ liệu ra: Ghi ra file văn bản baitoan5.out các số lẻ chỉ xuất hiện 1lần.
Ví dụ:
baitoan5.inp baitoan5.out
12231
Trang 11Chương trình:
Bài toán 6: Cho một dòng không quá 255 ký tự bao gồm các ký tự ‘0 9’, ‘a z’,
‘A Z’ (các ký tự viết dính liền với nhau), hãy kiểm tra tần suất xuất hiện của các
ký tự (phân biệt chữ hoa, chữ thường)
Dữ liệu vào: Cho trong file văn bản baitoan6.inp, gồm một dòng không
Trang 12ma:=ord(s[i]); {lay ma ascii}
if (ma in ss) or (ma in sn) or (ma in sh) then inc(b[ma]);
Trang 13Bài toán 7: Cho một dòng không quá 255 chỉ bao gồm các chữ cái (các ký tự
viết dính liền với nhau) Hãy tìm tần suất chữ cái xuất hiện nhiều nhất (không phân biệt chữ hoa, chữ thường)
Dữ liệu vào: Cho trong file văn bản baitoan7.inp, gồm một dòng không
Trang 14Bài toán 8: Tìm số nguyên dương bé nhất không có trong dãy A 1, A 2, , A n.
gồm các số nguyên dương không lớn hơn 32000
Dữ liệu vào: Cho trong file văn bản baitoan8.inp, dòng đầu tiên ghi số n,
dòng thứ 2 ghi dãy số nguyên dương A 1, A 2 , , A n
Dữ liệu ra: Ghi ra file văn bản baitoan8.out số nguyên dương bé nhất
không có trong dãy A 1 ,A 2 , ,A n
Trang 15A: Array[1 m] of Integer; B: Array[1 max] of Boolean; f:text;
end;
close(f);
END
Trang 16Thuật toán 2: Thuật toán sắp xếp nhanh (Quick sort)
Xuất phát từ tư tưởng chia để trị
Tư tưởng: Người ta phân bài toán thành các bài toán con, các bài toán conlại tiếp tục được phân thành các bài toán con nhỏ hơn, cứ tiếp tục như thế chođến khi ta nhận được bài toán con đã có thuật giải hoặc có thể dễ dàng đưa rathuật giải Sau đó kết hợp nghiệm của các bài toán con để nhận được nghiệm củabài toán con lớn hơn để cuối cùng nhận được nghiệm của bài toán cần giải
Thuật toán chia để trị có thể biểu diễn bằng mô hình đệ quy như sau:Procedure Chiadetri(A,x); {Tìm nghiệm x của bài toán A}
Begin
If (A đủ nhỏ) then baitoan(A)
Else
Begin
Phân A thành các bài toán con A1, , Am;
For i:=1 to m do Chiadetri (Ai,xi);
Kết hợp nghiệm xi của bài toán con Ai để được nghiệm củabài toán A;
Trang 17Thuật toán sắp xếp nhanh (Quick Sort)
Ý tưởng: Tư tưởng của thuật toán này là chia để trị, ta tìm cách chia đôi
dãy ban đầu bằng cách chọn ra một phần tử là canh (key) Từ dãy ban đầu, tất cảphần tử nhỏ hơn phần tử chốt thì đưa về bên trái dãy; những phần tử lớn hơnhoặc bằng key thì đưa về bên phải dãy Sau bước này ta có phần tử key là đứngđúng vị trí Dãy ban đầu được chia thành hai dãy con nằm hai bên key Tiếp tụcphân chia các dãy con theo cách tương tự cho đến khi mọi dãy con đều có độ dàibằng 1 Có thể chọn phần tử key nằm đầu, cuối, giữa dãy hoặc chọn ngẫu nhiênmột phần tử trong dãy
Thuật toán: Trường hợp sau chọn canh là phần tử giữa dãy
Sắp xếp một đoạn bất kỳ X[L] X[R] với điều kiện L<R
Bước 1: key=(L+R) div 2; K=X[key];
Bước 2: i:=L; j:=R;
Bước 3:
Nếu X[i]<K thì tăng i;
Nếu X[j]>K thì giảm j;
Bước 4: Nếu i<j thì đổi chỗ X[i] và X[j], quay lại bước 3;
Bước 5: Lặp lại bước 1 đến bước 3 với đoạn X[L] đến X[j] và X[i] đếnX[H] cho đến khi tất cả các đoạn có độ dài bằng 1
Xây dựng chương trình con quicksort:
Procedure quicksort(l,h:longint);
var i, j:longint; key, tg:longint;
Begin i:=l; j:=h; key:=X[(l+h) div 2];
repeat while b[i]>x do inc(i);
while b[j]<x do dec(j);
if i<=j then begin
Trang 18Bài toán 1: Bạn An và Bình học Đại học ở Hà Nội An muốn tìm hiểu về
các bến xe Buýt ở Hà Nội còn Bình thì lớn lên và sống ở Hà Nội nên Bình biết rất rõ về các bến xe và số lượng xe của các bến xe Hà Nội có N bến xe Buýt được đánh số từ 1 đến N, Bình đố An: Hãy chọn trong N bến xe Buýt một số xe sao cho tổng số xe của 3 bến bất kỳ được chọn không lớn hơn tổng số xe của cácbến còn lại và số lượng bến xe được chọn là nhiều nhất Phần thưởng là một chuyến dạo chơi bằng xe Buýt để ngắm thành phố Hà Nội Bạn hãy giúp An
Dữ liệu vào: từ file văn bản bai1.inp
- Dòng đầu tiên ghi số N cho biết số bến xe buýt (4≤ N≤104)
- Dòng tiếp theo ghi N số nguyên dương A1 AN (Ai là số lượng xe củabến xe thứ i, Ai≤102)
Dữ liệu ra: Ghi vào file văn bản bai1.out
- Dòng duy nhất ghi số lượng bến xe được chọn (các số trên một dòngghi cách nhau bởi một dấu cách
Trang 19dừng lại khi gặp một bến mà có S> Sum – S, khi đó số bến đã được chọn sẽ lànhiều nhất.
while a[i]<x do inc(i);
while a[j]>x do dec(j);
Trang 20Bài toán 2: Trong đợt tổ chức tham quan danh lam thắng cảnh của tỉnh Phú
Thọ, Ban tổ chức hội thi tin học trẻ tổ chức cho N đoàn (Đánh số từ 1 đến N)mỗi đoàn đi tham quan một địa điểm khác nhau Đoàn thứ i thăm địa điểm cáchkhách sạn Hoàng Đế di km (i=1, ,n) Hội thi có m xe đánh số từ 1 đến m (m≥n)
để phục vụ việc đưa các đoàn đi tham quan Xe thứ j có mức tiêu thụ xăng là vj
đơn vị thể tích/km
Yêu cầu: Hãy chọn N xe để phục vụ việc đưa các đoàn đi tham quan, mỗi
xe chỉ phục vụ một đoàn, sao cho tổng chi phí xăng cần sử dụng là ít nhất
Dữ liệu vào: File văn bản baitoan2.inp
- Dòng đầu tiên ghi hai số nguyên dương m, n
- Dòng thứ hai ghi các số nguyên dương d1, ,dn.
- Dòng thứ ba ghi các số nguyên dương v1, ,vm.
Kết quả: Ghi ra file văn bản baitoans.out
- Dòng đầu tiên ghi tổng số xăng cần dùng cho việc đưa các đoàn đitham quan (không tính lượt về)
- Dòng thứ i trong N dòng tiếp theo ghi chỉ số xe phục vụ đoàn i(i=1, ,n)
Ý tưởng:
Trang 21- Sắp xếp dãy số mức tiêu thụ xăng V của các xe theo thứ tự tăng dần.
- Sắp xếp dãy số quảng đường đi của các đoàn theo thứ tự tăng dần
- Mức tiêu thụ xăng thấp nhất là: Min = ∑dn-i+1*vi với i=1, ,n Chỉ số xephục vụ các đoàn là giá trị từ 1 đến n trong dãy ID
j:=h;
key:=v[(l+h) div 2];
repeat
while v[i]<key do inc(i);
while v[j]>key do dec(j);
if i<=j then
begin
tg:=v[i];
v[i]:=v[j];
Trang 22v[j]:=tg; tg1:=id[i]; id[i]:=id[j]; id[j]:=tg1; inc(i);
dec(j); end;
while d[i]>key do inc(i);
while d[j]<key do dec(j);
Trang 23Yêu cầu: Cho N con số xuất hiện trong N lần quay Bạn hãy giúp người dẫn
chương trình xác định số lần xuất hiện của con số may mắn
Dữ liệu vào từ file văn bản baitoan3.inp:
Dòng đầu là số N (1 N 104)
Dòng tiếp theo có N số là các số xuất hiện trong N lần quay
Kết quả ghi ra file văn bản baitoan3.out:
Gồm một dòng duy nhất ghi số lần xuất hiện của con số may mắn
Trang 24d:=1;
while a[i]=a[i+1] do
begin inc(d); inc(i); end;
if d > max then Max:=d;
Trang 264 HIỆU QUẢ CỦA SÁNG KIẾN KINH NGHIỆM:
a Kết quả từ thực tiễn:
Qua quá trình nghiên cứu và vận dụng đề tài: “SỬ DỤNG THUẬT TOÁN ĐẾM PHÂN PHỐI VÀ THUẬT TOÁN SẮP XẾP NHANH (QUICH SORT) ĐỂ GIẢI MỘT SỐ BÀI TOÁN TIN HỌC’’, tôi nhận thấy đề tài này
giúp ích rất nhiều cho học sinh trong việc học bộ môn tin học 11 và ôn luyện thihọc sinh giỏi tin học, giúp các em không còn gặp khó khăn, lúng túng khi gặpchuyên đề này nữa, các em đã hiểu và vận dụng khá tốt thuật toán đếm phânphối và thuật toán sắp xếp vào lập trình giải các bài toán và từ các thuật toán nàycác em đã phát triển khả năng tư duy sang các thuật toán khác trong ngôn ngữlập trình; một số em đã bước đầu sáng tạo được những cách giải hay, cách giải.Riêng về bản thân tôi sẽ tiếp tục nghiên cứu sâu hơn nữa về chuyên đề này đểhọc sinh đam mê thích học và đạt nhiều thành tích hơn nữa trong việc học bộmôn Tin học
b Kết quả thực nghiệm:
Sáng kiến được áp dụng trong năm học 2016-2017; bài kiểm tra trên đốitượng lớp 11A1, 11A2, 11A3 và đội tuyển Tin học năm học 2016-2017 áp dụngsáng kiến so với kết quả học tập của các lớp năm học trước như sau:
Xếp loại Đối tượng