SỞ GIÁO DỤC VÀ ĐÀO TẠO THANH HOÁ TRƯỜNG THPT LÊ LỢI SÁNG KIẾN KINH NGHIỆM TÊN ĐỀ TÀI: SỬ DỤNG THUẬT TOÁN ĐẾM PHÂN PHỐI ĐỂ GIẢI MỘT SỐ BÀI TOÁN TIN HỌC Ở TRƯỜNG THPT LÊ LỢI, THỌ XUÂN, THA
Trang 1SỞ GIÁO DỤC VÀ ĐÀO TẠO THANH HOÁ
TRƯỜNG THPT LÊ LỢI
SÁNG KIẾN KINH NGHIỆM
TÊN ĐỀ TÀI:
SỬ DỤNG THUẬT TOÁN ĐẾM PHÂN PHỐI ĐỂ GIẢI MỘT
SỐ BÀI TOÁN TIN HỌC Ở TRƯỜNG THPT LÊ LỢI, THỌ
XUÂN, THANH HÓA
Người thực hiện: Lê Thị Huyên Chức vụ: Giáo viên
SKKN thuộc lĩnh vực (môn): Tin học
THANH HÓA NĂM 2021
Trang 2MỤ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 2
1.3 Đối tượng nghiên cứu 2
1.4 Phương pháp nghiên cứu 2
2 NỘI DUNG SÁNG KIẾN KINH NGHIỆM 2.1 Cơ sở lý luận 2
2.2 Thực trạng của vấn đề … 3
2.3 Các giải pháp giải quyết vấn đề 3
2.4 Hiệu quả của SKKN … 15
3 KẾT LUẬN, KIẾN NGHỊ … 16
Trang 31.MỞ ĐẦU
1.1 Lí do chọn đề tài.
Bồi dưỡng học sinh giỏi là một nhiệm vụ quan trọng đối với mỗi giáo viên Do
đó, việc nghiên cứu, tìm tòi, tích lũy kiến thức là công việc thường nhật của mỗi giáoviên nhằm nâng cao trình độ chuyên môn nghiệp vụ, tích lũy kinh nghiệm cho bảnthân
Chúng ta biết rằng, để có kết quả cao trong kì thi tuyển chọn học sinh giỏi mônTin học nói chung thì học sinh phải có vốn kiến thức về thuật toán để giải được cácbài toán khó, sau đó học sinh sẽ sử dụng một ngôn ngữ lập trình nào đó để lập trìnhdựa vào thụật toán đã tìm được và giải bài toán theo yêu cầu Chương trình giảng dạy
ở sách giáo khoa của môn Tin học hiện hành trong trường THPT có lượng kiến thứcrất hạn chế và đơn giản, không đủ cơ sở và không thể là nền tảng để học sinh có thểdựa vào vốn kiến thức đó tham gia một kì thi học sinh giỏi cấp tỉnh hay cao hơn Câu
hỏi đặt ra là: Làm thế nào để học sinh có thể đạt kết quả cao trong các kì thi học
sinh giỏi môn Tin học trong trường THPT?
Xuất phát từ việc trực tiếp bồi dưỡng học sinh giỏi nhiều năm, bản thân tôinhậ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ácbà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ựchiệ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 cần 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 khi giải các bài toán tin có liên quan đến thuật toánnâ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ánhiệu quả Vì vậy, để giúp học sinh tháo gỡ được những khó khăn, vướng mắc trongquá trình học tập, ôn luyện thi học sinh giỏi, thì bản thân tôi không ngừng học hỏitrướ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 ranhữ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ơnnữ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 bồi dưỡng học sinh giỏi với đề tài: “ Sử dụng thuật toán đếm phân phối để giải
một số bài toán tin học ở trường THPT Lê Lợi, Thọ Xuân, Thanh Hóa”
Trang 4Trong quá trình triển khai đề tài, bản thân tôi tự thấy đã có những kết quả nhất định, muốn được chia sẻ với các bạn đồng nghiệp Hi vọng sẽ nhận được nhiều ý kiến bổ ích để đề tài của tôi ngày một hoàn thiện hơn
1.2 Mục đích nghiên cứu:
Áp dụng đề tài này tôi hướng tới những mục đích sau:
- Giúp học sinh hiểu và vận dụng tốt thuật toán đếm phân phối để giải quyết
được các bài toán cơ bản và nâng cao
- Nâng cao chất lượng bồi dưỡng học sinh giỏi.
- Giúp học sinh thêm yêu thích bộ môn Tin học hơn.
1.3 Đối tượng nghiên cứu:
- Học sinh khối 11 trường THPT Lê Lợi
- Nghiên cứu khái quát về chương trình môn Tin học 11 nói chung và thuậttoán đếm phân phối nói riêng
- Một số chuyên đề nâng cao bồi dưỡng học sinh giỏi
- Nghiên cứu hoạt động dạy và học của học sinh và giáo viên trong trườngTHPT
1.4 Phương pháp nghiên cứu:
- Phương pháp điều tra khảo sát thực tế.
- Phương pháp thu thập thông tin
- Phương pháp thống kê, xử lí số liệu, so sánh
quả ta sử dụng thuật toán Đếm phân phối
Trang 5Tư tưởng của thuật toán Đếm phân phối đượ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úngvà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àomột chuồng thì càng tốt Tương tự như vậy, muốn giải bài toán đếm cá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
2.2 Thực trạng vấn đề trước khi áp dụng sáng kiến kinh nghiệm
- Môn Tin học lớp 11 là môn khoa học tự nhiên không dễ đối với học sinh Hơnnữa, đó là môn không thi tốt nghiệp và đại học nên chưa được học sinh, phụ huynhquan tâm đúng mức Dẫn đến việc tuyển chọn đội tuyển học sinh giỏi gặp nhiều khókhăn
- Khi chưa áp dụng sáng kiến này thì khi học sinh gặp các bài toán đếm các emthường gặp khó khăn ở các bài toán có miền dữ liệu lớn Các em rất lúng túng trongquá trình phân tích bài toán, tổ chức dữ liệu, tìm ra thuật toán hiệu quả để lập trìnhgiải các bài toán
2.3 Các giải pháp 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ầuvớ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ờigiải tốt để tiếp cận và xử lý được các bài toán đếm
Thuật toán: Thuật toán đếm phân phối (hay còn gọi là lùa bò vào chuồng)
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 lớn con bò trên một cánh đồng rộng thì người ta phải tìm cách lùa chúng vàocá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àomột chuồng thì càng tốt Tương tự như vậy, muốn giải bài toán đếm cá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
Trang 6học sinh giỏi tôi đã đưa ra các bài toán sau:
Bài toán mở đầu: Giả sử trên cánh đồng rộng thả rất nhiều bò (N con, N rất
lớn), 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ấtnhiê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 < 5x108) và các phần tử của mả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(20) = {1,2,3,6,4,5,6,0,5,6,7,1,6,0,5,6,8,9,1,9} thì A(20) có số phần
tử giá trị bằng 6 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 ” như sau:
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 mọ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]])
Trang 7End;
{Khởi tạo dãy chuồng bò ban đầu chưa có bò}
Fillchar (B, sizeof (B) ,0) ; {Thực hiện lùa bò vào chuồng}
For i := 1 to N do inc (B [A[i] ] );
Hướng dẫn:
Để giải bài toán này ta dùng thuật toán “đếm phân phối” (hay còn gọi là thuật
toán lùa bò vào chuổng) Các phần tử có giá trị bằng nhau sẽ nhốt chung vào một
Trang 8chuồng, có bao nhiêu chuồng khác trống thì có bấy nhiêu phần tử khác nhau trong dãy
đã cho
Ta đóng dãy chuồng B, đánh số chuồng lần lượt từ 1,2….107 (ai là các sốnguyên dương, ai<1000), 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 đơn vị) Đếm sốchuồng khác trống đó chính là số phần tử khác nhau của dãy ban đầu
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,…,an các
phần tử nguyên dương 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’
- 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)
Trang 9{lua bo vao chuong}
for i:=1 to n do inc(b[a[i]]);
assign(f, ‘Baitoan3.out’); rewrite(f);
{dua ra day duoc sap xep}
for i:=1 to 32000 do for j:=1 to b[i] do write(f,i,' ');
Jack đã 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 ‘Baitoan4.inp’
- Dòng 1 chứa số nguyên dương n (1 ≤ n ≤ 106);
Trang 10- n dòng sau, dòng thứ i chứa một số nguyên dương ai (1≤ ai < 10 6)
Kết quả: Đưa ra file văn bản ‘Baitoan4.out’ gồm một số là số lượng các số chỉ
xuất hiện một lần
Ví dụ:
5 1 4 1 3 2
Trang 11If B[A[i]]=1 then dem:=dem+1;
Dữ 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<=<=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.
Chương trình:
Const input= ‘Baitoan5.inp’; output= ‘Baitoan5.out’;
Var a: array[1 1000] of integer;
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’, hãy kiểm tra tần suất xuất hiện của các kí tự (không 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 quá
Trang 12Bài toán 7: Cho một dòng không quá 255 kí tự chỉ bao gồm các chữ cái Hãy
tìm tần suất xuất hiện 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 quá
255 kí tự
Dữ liệu ra: Ghi ra file văn bản ‘Baitoan7.out’ tần suất chữ cái xuất hiện nhiều
nhất
Chương trình:
Trang 13Const input= ‘Baitoan7.inp’; output= ‘Baitoan7.out’;
Bài toán 8: Tìm số nguyên dương bé nhất không có trong dãy a1, a2, , an,
gồm các số nguyên không lớn hơn 32000
Dữ liệu vào: Cho trong file văn bản ‘Baitoan8.inp’, gồm dòng đầu tiên ghi số n
(0<n<100), dòng thứ hai ghi dãy số nguyên dương a1, a2, , an
Dữ liệu ra: Ghỉ ra file văn bản ‘Baitoan8.out’ số nguyên dương bé nhất không
có trong dãy a1, a2, , an
Chương trình:
Trang 14Const max=32000;
Input= ‘Baitoan8.inp’; Output= ‘Baitoan8.out’;
Var i, j, n: Integer; f: Text;
Fillchar(B, sizeof(b), False);
For i:=1 to max do
If b[i] = False then Begin
Bài tập tương tự, bài tập nâng cao:
Sau khi học sinh đã nắm vững và biết cách sử dụng thuật toán đếm phân phối
để giải quyết được các bài toán đếm cơ bản, tôi tiếp tục cung cấp một số bài tập tương
tự và nâng cao nhằm củng cố thuật toán và giúp học sinh khai thác thuật toán mộtcách linh hoạt, sáng tạo
Bài 1 : Tập con
Cho tập A có N phần tử {a 1 , a 2 ,…, a N }, tập B được gọi là tập con của tập A nếu tập B
có M phần tử {b 1 , b 2 ,…,b m }thỏa mãn các điều kiện: Các phần tử từ tập B được lấy từ tập A (b i thuộc A, với mọi i=1 m) và các phần tử trong tập B khác nhau từng đôi một (b i ≠ b j , i≠j).
Ví dụ: cho tập A= {1, 9, 4, 5, 9, 5, 8, 9} thì tập B ={1, 4, 5, 8, 9}
Yêu cầu: Tìm tập B sao cho số phần tử của B là lớn nhất.
Dữ liệu vào: Ghi trong tệp BAI1.INP
- Dòng 1: số nguyên dương N(1 <= N<= 10000).
- Dòng 2: Ghi N số nguyên dương, số thứ i là giá trị của phần tử a i trong tập A(1<=i
<= N, 0< a i < =32000) Các số được ghi cách nhau ít nhất một dấu cách.
Trang 15Dữ liệu ra: Ghi vào tệp BAI1.OUT theo cấu trúc:
- Dòng 1: Ghi số nguyên dương m là số lượng phần tử của tập B tìm được.
- Dòng 2: Ghi m số nguyên dương, số thứ i là giá trị phần tử b i trong tập B tìm được Các số được ghi cách nhau một dấu cách.
- Tính tần số xuất hiện các chữ số của N;
- Viết liên tiếp tần số và chữ số theo thứ tự tăng dần của các chữ số khác nhau trong N.
Ví dụ: với N = 353, ta có tần số xuất hiện của 3 là 2, tần số xuất hiện của 5 là 1 Như vậy số thống kê sẽ là 2315.
Dữ liệu vào: Đọc từ tệp BAI2.INP gồm 1 chữ số N
Dữ liệu ra: Ghi lên tệp BAI2.OUT số thống kê của N.
Dữ liệu vào từ tệp BAI3.INP
- Dòng thứ nhất là chiều dài n của mảng (1≤ n ≤10 5 )
- Dòng thứ hai gồm n số nguyên a 1 , a 2 , a 3 , a n (1≤ a i ≤10 5 ), mỗi số cách nhau một khoảng trắng.
Dữ liệu ra ghi vào tệp BAI3.OUT - Là số nguyên xác định số lượng các cặp bằng nhau.
Bài 4: Chữ cái xuất hiện (HSG Thanh Hóa 2011-2012)
Cho xâu St chỉ gồm các chữ cái Tính số lần xuất hiện của chữ cái xuất hiệnnhiều nhất trong xâu (không phân biệt chữ in hoa và in thường)
Dữ liệu vào: Từ file BAI4.INP gồm: Xâu St (độ dài <=500 kí tự)
Trang 16Kết quả: Ghi ra filr BAI4.OUT gồm: Một dòng duy nhất là bội số chung nhỏ nhất
của kết quả bài toán và 105
Ví dụ:
Bài 5: Kí tự khác nhau (HSG Thanh Hóa 2016-2017)
Cho xâu s chỉ gồm các kí tự là chữ cái tiếng Anh và các chữ số (có phân biệtchữ in hoa, in thường)
Yêu cầu: Hãy xác định số kí tự khác nhau trong xâu S và mỗi kí tự xuất hiện bao
nhiêu lần
Dữ liệu vào: Vào từ file văn bản BAI5.INP gồm một dòng duy nhất là xâu kí tự S (có
độ dài không quá 255)
Kết quả: Ghi ra file văn bản BAI5.OUT gồm:
- Dòng đầu ghi số kí tự khác nhau
- Các dòng tiếp theo, mỗi dòng ghi một kí tự xuất hiện trong xâu S và tần sốxuất hiện của nó Các kí tự đưa ra theo thứ tự chữ cái in hoa, in thường, chữ
số Các chữ cái, chữ số đưa ra theo thứ tự từ điển
Hai từ gọi là bạn bè nếu chúng được tạo nên bởi cùng một tập hợp kí tự giống
nhau: Ví dụ S1=’aabbbccccb’ và S2=’aabccccaaaaa’ là bạn bè vì nó cùng được tạo bởi tập ký tự {‘a’,’b’,’c’} Cho ba cặp hai từ; với mỗi cặp in ‘YES’ nếu hai từ
trong cặp là bạn bè và in ‘NO’ nếu chúng không phải là bạn bè
Dữ liệu vào: vào từ file ‘BAI6.INP’ gồm 6 xâu ký tự (mô tả 6 từ) lần lượt là S1, S2,
S3, S4, S5, S6; mỗi xâu trên một dòng chỉ gồm chữ cái tiếng Anh in thường có độ dàikhông vượt quá 106
Trang 17Dữ liệu ra: Ghi vào file ‘BAI6.OUT’ gồm ba dòng:
- Dòng 1: In ‘YES’ nếu S1 và S2 là bạn bè, ngược lại in ‘NO’
- Dòng 2: In ‘YES’ nếu S3 và S4 là bạn bè, ngược lại in ‘NO’
- Dòng 3: In ‘YES’ nếu S5 và S6 là bạn bè, ngược lại in ‘NO’
Bài 7: Tập số (HSG Thanh Hóa 2016-2017)
Cho số tự nhiên N (1<=N<=106) và một tập A chỉ gồm các số tự nhiên khácnhau được xác định như sau:
- 1 thuộc A
- Nếu k thuộc A thì 2k+1 và 3k+1 cũng thuộc A
Yêu cầu: Giả sử tập A đã được sắp xếp theo thứ tự tăng dần Hãy tìm phần tử thứ N
của tập A
Dữ liệu vào: Vào từ file văn bản BAI4.INP gồm 1 dòng duy nhất chứa số N.
Kết quả: Ghi ra file văn bản BAI4.OUT gồm một số duy nhất là phần tử thứ N của
tập A tìm được
Ví dụ:
2.4 Hiệu quả của sáng kiến kinh nghiệm.
Qua quá trình triển khai đề tài tôi nhận thấy đã thu được kết quả thực sự Đó là:
- Đa số học sinh đã nắm được các kiến thức, kỹ năng của bài học