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

SK dem don gian bang thuat toan lua bo vao chuong

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 (158.84 KB, 23 trang )

Sáng kiến: ĐẾM ĐƠN GIẢN BẰNG THUẬT TỐN LÙA BỊ VÀO CHUỒNG
1. ĐẶT VẤN ĐỀ:
1.1. Lý do chon đề tài:
Trong thời đại khoa học và công nghệ ngày nay, nhân lực có trình độ cao khơng chỉ là
tiền đề mà cịn là yếu tố có tính quyết định cho sự phát triển của một đất nước. Để tạo nguồn
nhân lực có trình độ cao thì vấn đề phát hiện, bồi dưỡng và sử dụng người tài có vai trị quan
trọng. Nhận thức được vai trò quan trọng của nhân tài, Đảng và Nhà nước ta đã có những chủ
trương, chính sách để phát hiện và bồi dưỡng nhân tài. Để góp phần thực hiện chủ trương đó,
ngành Giáo dục cần chú trọng nâng cao chất lượng bồi dưỡng học sinh giỏi ngay từ bậc học
cơ sở, các nhà quản lý phải đề ra được những biện pháp quản lý dạy học bồi dưỡng học sinh
giỏi để công tác này đạt kết quả cao nhất. Chính vì vậy, nhiệm vụ chính trị quan trọng của
người giáo viên là nghiên cứu, tìm tòi, đúc kết các kiến thức, biện pháp một cách khoa học để
bồi dưỡng học sinh giỏi đạt kết quả cao nhất.
Trong kỹ thuật lập trình, các bài tốn có liên quan đến đếm các đối tượng rất gần gũi
và dễ giải đối với chúng ta vì tính dễ xây dựng thuật tốn cho nó. Tuy nhiên, những bài tốn
″đếm″ thường yêu cầu với dữ liệu rất lớn. Nếu không biết tổ chức dữ liệu và thuật tốn hiệu
quả thì khó có thể đưa ra lời giải. Để hệ thống lại các chuyên đề bồi dưỡng HSG chuyên Tin
học mà tôi đã dạy trong nhiều năm qua, đồng thời qua quá trình nghiên cứu, giảng dạy, tham
khảo ý kiến với đồng nghiệp,..., tơi thấy rằng một số bài tốn Tin học có liên quan đến việc
đếm. Chính vì vậy, một trong những cách tiếp cận để xử lý hiện tượng này là “ĐẾM ĐƠN
GIẢN BẰNG THUẬT TỐN LÙA BỊ VÀO CHUỒNG”.
1.2. Xác định mục đích nghiên cứu:
Đếm là cơng việc quan trọng và đơn giản mà chúng ta làm thường ngày, điều đó thì
khơng cần phải bàn đến làm gì? Điều đáng nói ở đây là cơng việc có vẽ nhàm chán đó lại
chứa bao điều thú vị, nhất là khi gặp những bài toán yêu cầu ta phải đếm. Đếm ở đây không
phải đơn thuần là đếm 1, 2, 3, ... mà còn cần ở người đếm một sự khéo léo về tổ chức dữ liệu
và có thể có một chút kỹ thuật. Bên cạnh đó giúp các em học sinh có kiến thức tốt, tư duy tốt
về lập trình. Các phương pháp đếm đơn giản là một trong những vấn đề mà bất cứ người lập
trình tin học đều cần phải nắm vững.
1.3. Đối tương nghiên cứu
Trong nghiên cứu này, tơi chỉ tập trung vào tìm hiểu và giải quyết một số bài toán Tin


học liên quan đến việc đưa các giá trị giống nhau vào cùng một "chuồng", sau đó duyệt lại
các "chuồng" và tìm hay đếm "chuồng" có giá trị thỏa mãn u cầu bài tốn. Hay nói một
cách khác là giải quyết một số yêu cầu bài tốn Tin học bằng thuật tốn "Lùa bị vào chuồng".
1.4. Đối tượng khảo sát, thực nghiệm:
Đối tượng khảo sát, thực nghiệm ở đây là các em học sinh chọn và bồi dưỡng để dự
thi học sinh giỏi Tin cấp huyện, các em học sinh giỏi Tin lớp 9 ở huyện được chọn và bồi
dưỡng dự thi học sinh giỏi cấp tỉnh, bồi dưỡng giáo viên dự thi giáo viên dạy giỏi cấp huyện,
cấp tỉnh.
GV: Nguyễn Trương Tiên

1

Năm học: 2016-2017


Sáng kiến: ĐẾM ĐƠN GIẢN BẰNG THUẬT TỐN LÙA BỊ VÀO CHUỒNG
1.5. Các phương pháp nghiên cứu
Phương pháp suy luận, tổng hợp: kết hợp từ nhiều nguồn tài liệu tham khảo của các tác
giả và tra cứu trên mạng internet với các bài tập, các đề thi Học sinh Giỏi các cấp rút ra những
kinh nghiệm, hệ thống lại kiến thức, mở ra các hướng mới.
Phương pháp trò chuyện - phỏng vấn: trao đổi tâm tình với nhiều học sinh giỏi để nắm
tình hình trong việc giải các bài tốn tin.
Phương pháp khảo sát: bản thân được tham gia giảng dạy các lớp, đội tuyển HSG, các
kỳ tập huấn, ra đề; tham khảo đồng nghiệp, quý Thầy Cô đã giảng dạy đội tuyển nhiều năm
nên có nắm được tình hình sử dụng các phương pháp làm bài của các em học sinh.
Phương pháp phân tích lý luận: phân tích giúp học sinh nắm thật rõ bản chất vấn đề,
lựa chọn được phương pháp giải cho phù hợp.
1.6. Phạm vi và thời gian nghiên cứu:
Trong đề tài này, tôi chỉ nghiên cứu ở phạm vi nhỏ là sử dụng thuật toán "Lùa bị vào
chuồng" để "đếm" một số bài Tốn Tin liên quan.

Để hồn thành đề tài này, tơi đã tiến hành sưu tầm, tìm hiểu, nghiên cứu kể từ đầu năm
học 2014-2015 cho đến nay.
2. NỒI DUNG:
2.1. Cơ sở lý luân của đề tài
Trong những năm liên tiếp dạy bồi dưỡng HSG môn Tin Học lớp 8, 9 và đội tuyển thi
HSG cấp Huyện, cũng như tham khảo ý kiến các đồng nghiệp chuyên dạy bồi dưỡng đội
tuyển ở Huyện, ở các trường THCS, THPT, tôi rút ra một điều là “CƠNG VIỆC ĐẾM RẤT
QUAN TRỌNG TRONG DẠY LẬP TRÌNH”. Được sự động viên khuyến khích của q
Thầy/Cơ trong tổ cũng như các giáo viên tham gia bồi dưỡng, tôi mạnh dạng chọn viết đề tài
“ĐẾM ĐƠN GIẢN BẰNG THUẬT TỐN LÙA BỊ VÀO CHUỒNG”. Đề tài có sự kết hợp
bài giảng và các tài liệu tham khảo để phân tích, tổng hợp, hệ thống.
2.2. Thưc trang của vấn đề nghiên cứu
Đa số học sinh, giáo viên tham gia bồi dưỡng môn Tin học rất ngại, sợ khi giải các bài
tốn Tin học có liên quan đến việc đếm; rất lúng túng trong q trình phân tích, tổ chức dữ
liệu, tìm ra thuật tốn hiệu quả để tìm ra bản chất và vận dụng kiến thức một cách thích hợp.
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 một số “dạng bài tốn tin có liên quan đến việc
đếm”; 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, đồng thời
trao đổi và học tập kinh nghiệm ở Quý Thầy Cô ở bộ môn Tin học trong huyện cũng như một
số huyện trong tỉnh.
2.3. Mô tả, phân tích các giải pháp:
Trong kỹ thuật lập trình, các bài tốn có liên quan đến đếm các đối tượng rất gần gũi
và dễ giải đối với chúng ta vì tính dễ xây dựng thuật tốn cho nó. Tuy nhiên, những bài toán
GV: Nguyễn Trương Tiên

2

Năm học: 2016-2017



Sáng kiến: ĐẾM ĐƠN GIẢN BẰNG THUẬT TỐN LÙA BỊ VÀO CHUỒNG
“đếm” thường yêu cầu với dữ liệu rất lớn. Nếu khơng biết tổ chức dữ liệu và thuật tốn hiệu
quả thì khó có thể đưa ra lời giải tốt. Một trong những cách tiếp cận để xử lý hiện tượng này
là sử dụng thuật tốn “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
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 đếm các đối tượng thì ta dùng một cấu trúc dữ liệu hợp lý (thường là mảng
tĩnh hay mảng độ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.
Bài 1: Đếm bò

Tên chương trình: Dembo.pas

Bài tố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 ngun 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 tố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 ≤ 200) 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(12) = {2,3,2,4,5,6,2,6,7,1,6,2} thì A(12) có số phần tử giá trị bằng 2 là nhiều
nhất. Số lượng phần tử này xuất hiện 4 lần.
a/ Cách 1: Chưa vận dụng thuật tốn “Lùa bị vào chuồng”:
* Ý tưởng: Dùng hai vòng lặp i (1≤i≤N) và j (1≤j≤N) lồng nhau. Với mỗi giá trị tại
A[i], ta đếm số lần xuất hiện tương ứng A[j]. So sánh số lần xuất hiện giữa hai giá trị A[i] và
A[i+1], ta lấy giá trị xuất hiện nhiều hơn.
Thuật toán:

+Input: Số nguyên dương N và dãy N số nguyên dương A.
+Output: Giá trị xuất hiện nhiều nhất ứng với số lần xuất hiện trong dãy A.
-Bước 1: Nhập N và dãy số nguyên A.
-Bước 2: Max←0;i←0;
-Bước 3: i←i+1; Nếu i>N thì chuyển Bước 8.
-Bươc 4: dem←1;j←0;
-Bước 5: j←j+1; Nếu j>N thì chuyển đến Bước 7.
-Bước 6: Nếu i<>j và A[i]=A[j] thì dem←dem+1; Quay lại Bước 5.
-Bước 7: Nếu dem>Max thì Max←dem và gt←A[i]; Quay lại Bước 3.
GV: Nguyễn Trương Tiên
3
Năm học: 2016-2017


Sáng kiến: ĐẾM ĐƠN GIẢN BẰNG THUẬT TỐN LÙA BỊ VÀO CHUỒNG
-Bước 8: Thông báo giá trị Max và gt; Kết thúc thuật tốn.

* Chương trình mẫu:
uses crt;
var A:array[1..50]of word;
n:word;
procedure nhap;
var i:word;
begin
clrscr;
write('Cho biet so luong bo=');
readln(n);
writeln('Nhap tuoi cho moi con bo:');
for i:=1 to n do
begin

write('A[',i,']=');
readln(A[i]);
end;
end;
procedure xuly;
var i,j,max,dem,gt:word;
begin
max:=0;
for i:=1 to n do
begin
dem:=1;
for j:=1 to n do
if (i<>j) and (a[i]=a[j]) then
inc(dem);
if dem>max then
begin
max:=dem;
gt:=A[i];
end;
end;
Write('So ’,gt,’ co so luong lon nhat la ',Max);
end;
begin
nhap;
xuly;
readln;
end.
b/Cách 2: Vận dụng thuật tốn “Lùa bị vào chuồng”
Để giải bài tốn này người ta dùng thuật tốn “lùa bị vào chuồng” gồm 3 bước:
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.
GV: Nguyễn Trương Tiên

4

Năm học: 2016-2017


Sáng kiến: ĐẾM ĐƠN GIẢN BẰNG THUẬT TỐN LÙA BỊ VÀO CHUỒNG
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 tố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]])
Bước 3: Duyệt mảng b, tìm chỉ số phần tử lớn nhất.
* Lưu ý: Do đề cho 0 < A[i] ≤ 100, tuy nhiên, thường bộ dữ liệu để kiểm tra không đến
số 100. Nên để việc duyệt mảng B tối ưu, ta cần một biến để lưu giữ giá trị lớn nhất trong
mảng A.
Chương trình tham khảo
Uses crt;
Const max = 200;
Var N: integer;
A: array[1..max] of byte;
B: array[1..max] of byte; maxs1, maxA, i, li:integer;
BEGIN
Clrscr;

Write('Nhap so nguyen duong N = ’);Readln(N); MaxA:=0;
For i := 1 to N do
Begin
Write('A[',i:2,'] = ’);Readln(A[i]); if A[i]>MaxA then MaxA:=A[i];
End;
Fillchar (B, sizeof (B) ,0) ; {Tao day chuong bo rong chua co bo}
For i := 1 to N do
inc (B [A[i] ] ) ; {Tang them 1 con bo vao chuong co so hieu A[i]}
maxsl := 0; li:=0;
For i := 1 to MaxA do {Duyet day chuong tim chuong co nhieu bo nhat}
if B[i] > maxsl then
Begin
maxsl := B[i]; li := i;
End;
Write('So ’,li,’ co so luong lon nhat la ',B[li]); Readln;
END.
* Giữa hai cách giải trên, rõ ràng cách giải bằng thuật tốn "Lùa bị vào chuồng" có độ
phức tạp nhỏ hơn nhiều, thuật toán ngắn gọn, thời gian xử lý ngắn vì đơn thuần chỉ 1 vịng
lặp, cịn cách giải thứ nhất phải sử dụng hai vòng lặp lồng nhau (duyệt theo chiều sâu) với
mỗi giá trị đều phải xuất phát từ đầu.
* Do đề chỉ yêu cầu tìm số xuất hiện nhiều nhất và giá trị tương ứng nên ở cách 2, ta gặp
vấn đề lãng phí về bộ nhớ (mảng B). Do đó, để tối ưu về bộ nhớ, ta "lùa tất cả các con bò
cùng tuổi vào cùng chuồng " trong mảng A. Dĩ nhiên, ban đầu trong mỗi chuồng chưa có con
GV: Nguyễn Trương Tiên

5

Năm học: 2016-2017



Sáng kiến: ĐẾM ĐƠN GIẢN BẰNG THUẬT TỐN LÙA BỊ VÀO CHUỒNG
bò nào nên tất cả các phần tử trong dãy A đều có giá trị 0.
Chương trình tham khảo
Uses crt;
Const max = 200;
Var N: integer;
A: array[1..max] of byte;
maxs1, maxA, x, i, li:integer;
BEGIN
Clrscr;
fillchar(A,sizeof(A),0)
Write('Nhap so nguyen duong N = ’);Readln(N); MaxA:=0;
For i := 1 to N do
Begin
Write('A[',i:2,'] = ’);Readln(x);
inc(A[x]); {Tang them 1 con bo vao chuong co so hieu x}
if x>MaxA then MaxA:=x;
End;
maxsl := 0; li:=0;
For i := 1 to MaxA do {Duyet day chuong tim chuong co nhieu bo nhat}
if A[i] > maxsl then
Begin
maxsl := A[i]; li := i;
End;
Write('So ’,li,’ co so luong lon nhat la ',A[li]); Readln;
END.
* Thông qua chương trình tham khảo này, rõ ràng ta thấy "thuật tốn: lùa bị vào chuồng"
tối ưu về bộ nhớ, chương trình ngắn gọn, độ phức tạp của thuật tốn được cải thiện rất nhiều
(chỉ phụ thuộc vào giá trị biến N)
* Dùng thuật tốn “Lùa bị vào chuồng” để giải quyết các bài tốn sau, thơng qua đó thấy

được rằng: Nếu khơng có thuật tốn này thì vệc giải quyết các bài toán sau là quá phức tạp.
Bài 2: Dự tiệc
Tên chương trình: Dutiec.pas
Ơng An đến dự một buổi tiệc. Buổi tiệc đã có N người (0 < N < 500.000). Mỗi người
dự tiệc đều được cài lên áo một bơng hoa trên đó có ghi một con số ngun dương X bất kì (X
< 106) cho biết người khách đó sẽ dự tiệc tại phịng có chỉ số X. Hầu hết các phịng đều có số
lượng khách là số chẵn, duy nhất chỉ có một phịng có số lượng khách là số lẻ. Để đảm bảo đủ
cặp cho việc khiêu vũ nên ban tổ chức cần tìm ra số hiệu của phịng khách có số lượng khách
là số lẻ để ghi số cho ông An.
Yêu cầu: Cho trước một danh sách khách dự tiệc cùng với các số trên áo của họ, hãy
giúp ban tổ chức tìm ra số hiệu của phịng khách có số lượng khách là số lẻ.
Dữ liệu vào: Cho trong file văn bản DUTIEC.INP, gồm:
■ Dòng đầu tiên ghi một số N cho biết số khách của buổi tiệc khi ông An đến.
■ Trong N dòng tiếp theo, mỗi dòng ghi một số nguyên dương cho biết con số ghi trên
áo của người khách thứ i.
Dữ liệu ra: Ghi ra file văn bản DUTIEC.OUT gồm một số nguyên dương duy nhất. Đó
là số hiệu của phịng có số lượng khách là số lẻ.
GV: Nguyễn Trương Tiên

6

Năm học: 2016-2017


Sáng kiến: ĐẾM ĐƠN GIẢN BẰNG THUẬT TỐN LÙA BỊ VÀO CHUỒNG
Ví dụ:

DUTIEC.INP
5
1

2
2
3
1

DUTIEC.OUT
3

u cầu của bài tốn này hiểu đơn giản là tìm giá trị của phần tử chỉ xuất hiện một lần.
Ta có thể giải quyết bài tốn này theo cách 1 của Bài 1. Tuy nhiên, độ phức tạp của thuật toán
lớn hơn nhiều. Để giải bài toán này, ta nên dùng thuật tốn “lùa bị vào chuồng” gồm 3 bước
như sau:
Bước 1: Đóng dãy phịng và đánh số các phòng bằng các số tự nhiên liên tiếp từ 1 đến
max (max là số hiệu lớn nhất của khách tham gia dự tiệc), ban đầu mọi phòng đều chưa có
người khách nào.
Bước 2: Đưa tất cả các người khách vào phòng ứng với số hiệu ghi trên áo.
Bước 3: Duyệt tất cả các phịng và tìm ra phịng có tổng số người khách trong phịng
là số lẽ thì phịng đó chính là phịng cần tìm.
* Lưu ý: Đề cho số hiệu ghi trên áo của người khách <10 6. Tuy nhiên, trong nhiều
trường hợp, số liệu kiểm tra khơng đến đấy. Vậy, để việc duyệt tìm phịng có số hiệu là lẽ
ngắn gọn, đỡ tốn thời gian, ta cần một biến để lưu giữ số hiệu lớn nhất của người khách tham
gia dự tiệc. Và để đỡ tốn bộ nhớ máy tính, ta chỉ cần mảng A để lưu giữ tổng số ứng với số
hiệu ghi trên áo trong cùng phịng.
Áp dụng thuật tốn vào bài tập:
-Input: N và mảng A có N phần tử chứa giá trị 0.
-Output: Số có giá trị là lẽ có trong mảng A.
+B1: Nhập N.
+B2: i←0; Max←0;
+B3: i←i+1; Nếu i>N thì chuyển đến bước 6.
+B4: Nhập giá trị x thứ i; A[x]←A[x]+1;

+B5: Nếu Max < x thì Max←x; Quay lại bước 3.
+B6: i←0; So←0;
+B7: i←i+1; Nếu i>Max thì chuyển đến bước 9.
+B8: Nếu A[i] mod 2 <>0 thì So←i; Quay lại bước 7.
+B9: In So tìm được và kết thúc thuật tốn.
uses crt;
var A:array[1..250]of byte;
N,max:longint; f:text;
GV: Nguyễn Trương Tiên

Chương trình tham khảo
procedure xuly;
var i:longint;
begin
7

Năm học: 2016-2017


Sáng kiến: ĐẾM ĐƠN GIẢN BẰNG THUẬT TỐN LÙA BỊ VÀO CHUỒNG
procedure kt_docdl;
assign(f,'dutiec.out');
var i,x:longint;
rewrite(f);
begin
for i:=1 to max do
assign(f,'dutiec.inp');
if a[i] mod 2<>0 then
{$I-} reset(f);{$I+}
begin

if IOResult>0 then
write(f,i);
begin
break;
rewrite(f);reset(f);
end;
end;
close(f);
fillchar(A,sizeof(A),0);
end;
readln(f,n);max:=0;
begin
for i:=1 to n do
kt_docdl;
begin
xuly;
readln(f,x); inc(A[x]);
end.
if x>max then max:=x;
end;
close(f);
end;
Bài 3: Chuổi kiểm tra
Tên chương trình: ChuoiKT.pas
Cho một file văn bản có n dịng (3 < n < 30000), mỗi dịng là một chuỗi S có tối đa
255 kí tự, các kí tự S[i] thuộc [‘a’..’z’,'0'..'9'] với 1 < i < length(S). Trong đó, chỉ có một chuỗi
S có số lần xuất hiện là một số lẻ, các chuỗi khác có số lần xuất hiện là số chẵn.
u cầu: Tìm chuỗi S (có số lần xuất hiện lẻ) đó.
Dữ liệu vào: từ file ‘CHUOIKT.inp’
■ Dịng đầu là một số nguyên n.

■ Dòng thứ i + 1 trong n dịng sau, mỗi dịng là một chuỗi kí tự (1 < i < n).
Kết quả: ghi vào file ‘CHUOIKT.out’ chứa chuỗi kí tự tìm được theo u cầu.
Ví dụ:
CHUOIKT.INP CHUOIKT.OUT
7
lop 9 tin
abcdef
bbcc
lop 9 tin
abcdef
bbcc
abcdef
abcdef
Bài toán này tương tư như bài toán số 2 (Dự tiệc) nhưng điểm khác biệt ở đây là mỗi
phần tử có giá trị là một chuỗi ký tự nên ta không thể tổ chức kiểu dữ liệu như bài 2.
Ở bài toán này, ta dùng mảng S để lưu tất cả các phần tử chuỗi theo đề, dùng mảng A
để đánh dấu vị trí của chuỗi tương ứng có trong S xuất hiện là số chẵn ứng với giá trị True
(Các phần tử xuất hiện với số lần là chẵn được lùa vào một chuồng), ban đầu mảng A có giá
trị là False. Sau đó duyệt lại tồn bộ mảng A, tại vi trí có giá trị là False thì phần từ tại vị trí
đó trong S chính là phần tử cần tìm.
Thuật tốn được minh họa thông qua các bước như sau:
GV: Nguyễn Trương Tiên

8

Năm học: 2016-2017


Sáng kiến: ĐẾM ĐƠN GIẢN BẰNG THUẬT TỐN LÙA BỊ VÀO CHUỒNG
- Input: N, mảng S lưu N chuỗi phần tử , mảng A có N phần tử có giá trị là False.

-Output: Phần tử trong S xuất hiện là số lẽ.
+B1: Nhập N, nhập mảng S, gán giá trị False cho tồn mảng A.
+B2: i←0;
+B3: i←i+1. Nếu i>n thì chuyển tới bước 8;
+B4: d←1;j←0;
+B5: j←j+1. Nếu j>n thì chuyển tới bước 7;
+B6: Nếu S[i]=S[j] và i<>j thì d←d+1; Quay lại bước 5;
+B7: Nếu d mod 2=0 thì a[i]←True; Quay lại bước 3;
+B8: i←0;
+B9: i←i+1; Nếu i>n thì chuyển tới bước 11;
+B10: Nếu A[i]=False thì in chuỗi S[i]. Ngược lại quay lại bước 9;
+B11: Kết thúc thuật tốn.
Chương trình tham khảo
uses crt;
const f1='chuoikT.inp';
f2='chuoiKT.out';
max=100;
var a:array[1..max]of boolean;
s:array[1..max]of string; n:word;f:text;
procedure khoitao_docdl;
var i:word;
begin
assign(f,f1);
{$I-};reset(f);{$I+}
if IOResult>0 then
begin
rewrite(f);reset(f);
end;
readln(f,n);
for i:=1 to n do readln(f,s[i]);

close(f);
assign(f,f2);rewrite(f);
end;
procedure xuly(n:word);
var i,j,d:word;
begin
fillchar(a,sizeof(a),false); {Mang a deu co gia tri False}
for i:=1 to n do
begin
d:=1;
for j:=1 to n do
if (s[i]=s[j]) and (i<>j) then
inc(d);
if d mod 2=0 then a[i]:=true; {Neu dem tai do co gia tri chan thi gan gia tri True cho a[i]}
end;
for i:=1 to n do
GV: Nguyễn Trương Tiên
9
Năm học: 2016-2017


Sáng kiến: ĐẾM ĐƠN GIẢN BẰNG THUẬT TỐN LÙA BỊ VÀO CHUỒNG
if a[i]=false then
begin
writeln(f,s[i]);
break;
end;
close(f);
end;
begin

khoitao_docdl;
xuly(n);
end.
Bài 4: Số lần xuất hiện của ký tự

Tên chương trình: kytu_xh.pas

Viết chương trình nhập vào từ bán phím một xâu kí tự S và thơng báo ra màn hình số lần
xuất hiện của mỗi chữ cái Tiếng Anh trong S (không phân biệt chữ hoa hay thường).
Ví dụ: Nhập vào xâu "TIN HOC"
Thơng báo ra màn hình:

C:1
H:1
I :1
N:1
O:1
T:1
Ở bài tốn này, nếu ta sử dụng phương pháp duyệt theo chiều sâu thì độ phức tạp rất lớn
và rất khó thực hiện việc thơng báo kết quả theo yêu cầu vì các ký tự được in ra theo một
trình tự theo alphabet. Để đơn giản, ta chỉ việc khai báo một mảng Dem ứng với mỗi ký tự là
một phần tử. Ban đầu mảng Dem này ứng với mỗi phần tử ký tự đều bằng 0. Sau đó duyệt
qua xâu S đã nhập, dồn các phần tử cùng loại có trong S vào mảng Dem (lùa vào cùng
chuồng) và tại đó tăng số lượng tương ứng đúng bằng số dồn vào. Điểm cần lưu ý ở đây là
trong xâu S có thể có nhiều ký tự khác chữ cái Tiếng Anh nên trong quá trình "lùa vào cùng
chuồng", ta chỉ lùa các chữ cái này.
Chương trình tham khảo
uses crt;
var dem:array['A'..'Z'] of byte;
s:string;ch,x:char;i:byte;

begin
clrscr;
write('Chuoi s=');readln(s);
fillchar(dem,sizeof(dem),0);
for i:=1 to length(s) do
begin
x:=upcase(s[i]);
if (x>='A') and (x<='Z') then {Chi dua vao cac chu cai Tieng Anh}
inc(dem[x]);
end;
GV: Nguyễn Trương Tiên

10

Năm học: 2016-2017


Sáng kiến: ĐẾM ĐƠN GIẢN BẰNG THUẬT TỐN LÙA BỊ VÀO CHUỒNG
for ch:='A' to 'Z' do
if dem[ch]>0 then
writeln(ch,':',dem[ch]);
readln;
end.
Mở rộng cho bài tốn này là u cầu có phân biệt chữ hoa, chữ thường.
Bài 5: Tổng các số khác nhau
Tên chương trình: tong_kn.pas
(Đề thi giáo viên dạy giỏi cấp tỉnh khối THCS năm học 2016-2017)
Cho mảng một chiều A gồm N số tự nhiên (0số khác nhau có trong mảng A (0Ví dụ: Cho mảng A:

2 5 1 2 1 2
Thì tổng cần tìm là: T=2+5+1=8
Bài tốn này có nhiều cách giải quyết, chẳng hạn như xét tại phần tử A i (1≤iqua tất cả các phần tử Aj (itổng giá trị các phần tử có trong A, khi đó tổng chính là giá trị cần tìm. Tuy nhiên rất mất thời
gian phải duyệt đi duyệt lại mảng A nhiều lần và làm thay đổi tính chất ban đầu của mảng A.
Để tối ưu và đơn giản hóa, ta áp dụng thuật tốn lùa bị vào chuồng như sau: Dùng mảng B để
đưa các phần tử cùng giá trị vào cùng một ơ tương ứng, sau đó duyệt lại mảng B, kiểm tra
xem phần tử nào trong B mà lớn hơn 0 thì cộng dồn vị trí tương ứng vào biến tổng T. Ban đầu
mọi phần tử trong B đều bằng 0.
Để giới hạn giá trị duyệt lại của mảng B, trong quá trình nhập liệu đầu vào, ta cần xác
định giá trị lớn nhất có trong A.
Thuật tốn được minh họa thông qua các bước như sau:
-Input: Giá trị N, mảng A chứa N phần tử, mảng B có các giá trị ban đầu đều bằng 0.
-Output: Tổng các giá trị khác nhau có trong A.
+B1: Nhập N.
+B2: i←0; Max←0;
+B3: i←i+1; Nếu i>N thì chuyển đến bước 6.
+B4: Nhập giá trị x thứ i; B[x]←B[x]+1;
+B5: Nếu Max < x thì Max←x; Quay lại bước 3.
+B6: i←0; T←0;
+B7: i←i+1; Nếu i>Max thì chuyển đến bước 9.
+B8: Nếu B[i] >0 thì T←T+i; Quay lại bước 7.
+B9: In tổng T tìm được và kết thúc thuật tốn.
Chương trình tham khảo
uses crt;
procedure xuly;
var B:array[1..201]of integer;
var i:longint;
N,max:word; f:text;T:longint;

begin
procedure kt_docdl;
assign(f,'Tong_KN.out');
GV: Nguyễn Trương Tiên

11

Năm học: 2016-2017


Sáng kiến: ĐẾM ĐƠN GIẢN BẰNG THUẬT TỐN LÙA BỊ VÀO CHUỒNG
var i:word;x:integer;
rewrite(f);T:=0;
begin
for i:=1 to max do
assign(f,'tong_KN.inp');
if B[i] >0 then
{$I-} reset(f);{$I+}
T:=T+i;
if IOResult>0 then
writeln(f,t);
begin
close(f);
rewrite(f);reset(f);
end;
end;
begin
fillchar(B,sizeof(B),0);
kt_docdl;
readln(f,n);max:=0;

xuly;
for i:=1 to n do
end.
begin
read(f,x);B[x]:=B[x]+1;
if x>max then max:=x;
end;
close(f);
end;
Bài 6: Tuyển nhân viên
Tên chương trình: Recruit.pas
Cơng ty phần mềm máy tính A có số lượng nhân viên rất lớn. Để tiện việc quản lý,
công ty đã cấp cho mỗi nhân viên một mã số, mã số của mỗi nhân viên là một số nguyên
dương, hai nhân viên bất kỳ thì có mã số khác nhau. Tuy nhiên, sau một thời gian thì một số
nhân viên đã nghỉ hưu hoặc chuyển công tác, nên công ty phải tiến hành tuyển thêm k nhân
viên mới. Các nhân viên mới này sau khi được tuyển vào cũng sẽ được cấp mã số, mỗi nhân
viên một mã số và mã số này cũng phải là một số nguyên dương.
Yêu cầu: Với n nhân viên hiện có (cịn lại) của cơng ty tương ứng với các mã số ai,
a2, ..., an. Hãy tìm k mã số nhỏ nhất để cấp cho k nhân viên mới tuyển vào sao cho vẫn thỏa
mãn hai nhân viên bất kỳ (cả nhân viên cũ và nhân viên mới) có mã số khác nhau.
Dữ liệu vào từ file ‘Recruit.inp’ có nội dung như sau:
■ Dịng đầu chứ hai số nguyên dương lần lượt là n và k (k < n < 106).
■ n dòng tiếp theo, dòng thứ i là số nguyên dương ai (i = 1, 2, ., n; ai < 2*109).
Kết quả ghi vào file ‘Recruit.out’ k mã số theo thứ tự từ nhỏ đến lớn (mỗi mã số trên
một dịng).
Ví dụ:
RECRUIT.INP RECRUIT.OUT
5 3
2
3

4
1
5
6
9
8
Hướng dẫn:
■ Cách 1: Thuật toán O(NlogN) dùng quicksort đủ chấp nhận.
■ Cách 2: Dùng Distribution sort O(n + K). Trong bài toán này, dãy chuồng chỉ cần đóng
GV: Nguyễn Trương Tiên

12

Năm học: 2016-2017


Sáng kiến: ĐẾM ĐƠN GIẢN BẰNG THUẬT TỐN LÙA BỊ VÀO CHUỒNG
số hiệu từ 1 đến số hiệu 2*nmax (nmax = 106) và mỗi chuồng chỉ chứa 1 trong 2 trạng thái đã
có hoặc chưa có (true, false). Bằng cách chạy từ 1 đến N, nếu số nào đã có thì đánh dấu
chuồng đó bằng true. Sau đó chạy từ 1 đến N+k, nếu số nào bằng false thì in số đó ra file (chỉ
in đủ k số).
Chương trình tham khảo
uses crt;
procedure xuly;
const f1='recreit.inp';
var i:word;
f2='E:recreit.out';
begin
ln=10000;
assign(f,f2);rewrite(f);

var N,K:word;f:text;
i:=1;
A:array[1..ln]of boolean;
while (K>0) and (i<=N+k) do
procedure khoitao_docdl;
if a[i]=false then
var i,x:word;
begin
begin
writeln(f,i);
assign(f,f1);
dec(k);inc(i);
{$I-} reset(f);{$I+}
end
if IOresult>0 then
else inc(i);
begin
close(f);
rewrite(f);reset(f);
end;
end;
begin
fillchar(A,sizeof(A),false);
khoitao_docdl;
readln(f,n,k);max:=0;
xuly;
for i:=1 to n do
end.
begin
readln(f,x);

A[x]:=true;
end;
close(f);
end;
Bài 7: Tần số

Tên tệp chương trình:Freq.pas
(Đề thi Olympic sinh viên 2001, khối đồng đội)
Cho một văn bản gồm khơng q N (N≤50) dịng, mỗi dịng chứa khơng quá 80 ký tự.
Ta gọi tần số của một ký tự trong văn bản là số lần xuất hiện của ký tự đó trong văn bản.
u cầu: Tìm tần số lớn nhất trong các tần số của các chữ cái (không phân biệt chữ hoa
hay chữ thường) trong đoạn văn bản đã cho.
Dữ liệu vào: từ file văn bản có tên là FREQ.INP:
Dòng đầu tiên chứa N là số lượng dòng văn bản.
N dòng tiếp theo mỗi dòng chứa một dòng của văn bản đã cho.
Kết quả: ghi ra file văn bản có tên FREQ.OUT tần số lớn nhất tìm được.
Ví dụ:
FREQ.INP
FREQ.OUT
4
25
faculty of technology
Hanoi National University
aaAAAAAaaaaAAAAaAaAaAa
cccCCCeeefffggg123456$#)(*+=
GV: Nguyễn Trương Tiên

13

Năm học: 2016-2017



Sáng kiến: ĐẾM ĐƠN GIẢN BẰNG THUẬT TỐN LÙA BỊ VÀO CHUỒNG
Hướng dẫn: Bài toán này tương tự như bài số 4. Chỉ khác ở đây là in ra tần số lớn
nhất tìm được và đề cho tất cả các ký tự (256 ký tự) chứ không chỉ là các chữ cái tiếng Anh.
Do đó ta khơng nên dùng mảng ký tự để lưu số lượng tương ứng được mà dùng mảng A có
256 phần tử dùng để lưu số lượng ký tự tương ứng. Ban đầu, mỗi phần tử trong A đều bằng 0.
Lần lược đọc hết các dòng văn bản cho trong tệp, cứ mỗi dòng, ta chuyển ký tự đọc được
thành số thứ tự tương ứng trong bảng mã ASCII ứng với giá trị k, sau đó tăng số lần xuất hiện
tại A[k] lần (A[k]←A[k]+1, tức là lùa các ký tự giống nhau vào cùng một ô). Sau đó duyệt lại
mảng A từ 1 cho đến 256 và tìm phần tử có giá trị lớn nhất thì đấy chính là giá trị cần tìm.
Lưu ý rằng đề cho không phân biệt chữ hoa hay chữ thường nên khi gặp chữ hoa, ta cộng
thêm cho 32 để trở thành chữ thường, tức là K←K+32.
Chương trình tham khảo
uses crt;
procedure output;
var a:array[1..256] of longint;
var f:text; i,m:longint;
n:integer;
begin
procedure solve;
assign(f,′FREQ.OUT′);
var f:text;i,j,k:integer;
Rewrite(f);
s:string; ss:set of byte;
m:=a[1];
begin
for i:=2 to 256 do
fillchar(a,sizeof(a),0);
if m < a[i] then m:=a[i];

ss:=[65..90]; {SS la cac ky tu hoa nhu A, B,...}
write(f,m); close(f);
assign(f,′FREQ.INP′);
end;
{$I-}reset(f); {$I+}
begin
if IOResult>o then
solve;
begin
output;
rewrite(f);reset(f);
end.
end;
readln(f,n);
for i:=1 to n do
begin readln(f,s);
for j:=1 to length(s) do
begin
k:=ord(s[j]); {Chuyen s[j] thanh so tuong ung}
if k in ss then k:=k+32; {chuyen chu thuong}
inc(a[k]);
end;
end;
close(f);
end;
Bài 8: Số nhỏ nhất

Tẻn tệp chương trình: Num_min.pas
( Đề thi chọn HSG tỉnh cấp THPT Hà Tĩnh)
Nam một người bạn của Nguyên đang tìm cách giải một bài toán liên quan tới số tự

nhiên và cần sự giúp đỡ của Nguyên, nhưng thử thách lần này là một dãy gồm N số tự nhiên
bất kỳ nằm trong đoạn từ 0 tới 10 9, tìm số tự nhiên nhỏ nhất khơng có trong dãy số đó. Vì số
lượng các só tự nhiên trong dãy số đã cho có thể lê tới 10 6 phần tử nên việc tìm thủ cơng là
khơng thể mà cần một thuật tốn để cài đặt vào máy tính và nhờ máy tính tìm giúp.
u cầu: Cho một dãy A gồm N (1≤N≤106) số tự nhiên. Hãy tìm số tự nhiên nhỏ nhất
GV: Nguyễn Trương Tiên
14
Năm học: 2016-2017


Sáng kiến: ĐẾM ĐƠN GIẢN BẰNG THUẬT TỐN LÙA BỊ VÀO CHUỒNG
khơng xuất hiện trong dãy A.
Ví dụ:
Dữ liệu vào
Kết quả
N=5
0
Dãy số: 5 4 3 2 1
N=9
5
Dãy số: 2 4 0 3 1 2 6 2 8
Bài toán này cũng có nhiều cách giải, tuy nhiên để tối ưu và đơn giản hóa, ta áp dụng
thuật tốn lùa bị vào chuồng như sau: Dùng mảng Dem để đưa các phần tử cùng giá trị vào
cùng một ô tương ứng, sau đó duyệt lại mảng Dem, kiểm tra xem phần tử nào trong Dem đầu
tiên mà bằng 0 thì giá trị cần tìm nhỏ nhất khơng có trong dãy số chính là vị trí tương ứng.
Ban đầu mọi phần tử trong Dem đều bằng 0. Vì gặp giá trị của phần tử nào, ta "lùa vào cùng
chuồng" nên để tối ưu bộ nhớ máy tính, ta khơng cần mảng để lưa dãy số đã cho.
Để giới hạn giá trị duyệt lại của mảng Dem, trong quá trình nhập liệu đầu vào, ta cần xác
định giá trị lớn nhất có trong dãy số.
Lưu ý: Do đề yêu cầu là các số nguyên dương nên giới hạn bé nhất trong mảng Dem là

từ số 0.
Thuật tốn được minh họa thơng qua các bước như sau:
-Input: Giá trị N và N giá trị tương ứng , mảng Dem có các giá trị ban đầu đều bằng 0.
-Output: Số nhỏ nhất khơng có trong dãy số đã cho.
+B1: Nhập N.
+B2: i←0; Max←0;
+B3: i←i+1; Nếu i>N thì chuyển đến bước 6.
+B4: Nhập giá trị x thứ i; Dem[x]←Dem[x]+1;
+B5: Nếu Max < x thì Max←x; Quay lại bước 3.
+B6: i←0;
+B7: i←i+1; Nếu i>Max thì chuyển đến bước 9.
+B8: Nếu Dem[i] =0 thì i chính là giá trị cần tìm; Ngược lại quay lại bước 7.
+B9: In giá trị i tìm được và kết thúc thuật tốn.
Chương trình tham khảo
uses crt;
procedure xuly;
var Dem:array[0..1000]of longint;
var i:longint;
N,max:longint; f:text;
begin
procedure kt_docdl;
assign(f,'Num_min.out');
var i,x:longint;
rewrite(f);
begin
for i:=0 to max do
assign(f,'Num_min.inp');
if dem[i]=0 then
{$I-} reset(f);{$I+}
begin

if IOResult>0 then
writeln(f,i);
GV: Nguyễn Trương Tiên

15

Năm học: 2016-2017


Sáng kiến: ĐẾM ĐƠN GIẢN BẰNG THUẬT TỐN LÙA BỊ VÀO CHUỒNG
begin
break;
rewrite(f);reset(f);
end;
end;
close(f);
fillchar(Dem,sizeof(Dem),0);
end;
readln(f,n);max:=0;
begin
for i:=1 to n do
kt_docdl;
begin
xuly;
read(f,x);Dem[x]:=Dem[x]+1;
End.
if x>max then max:=x;
end;
close(f);
end;

Bài 9: SỐ LƯỢNG NHĨM ĐỀ TÀI
Tên tệp chương trình: Nhom_DT.pas
( Đề thi chọn HSG tỉnh cấp THPT Hà Tĩnh)
Nhà trường phát động phong trào đăng ký làm sáng tạo khoa học kỹ thuật, tất cả các ban
trong lớp của Nguyên đều tích cực than gia và được phân cơng vào các nhóm đề tài. Mỗi
nhóm đề tài được ký hiệu: <Tên nhóm> <Số thành viên>, ví dụ Ngun được phân cơng vào
nhóm TIN gồm 3 thành viên thì ký hiệu nhóm là TIN 3. Danh sách được lập ra gồm ký hiệu
nhóm và tên thành viên, nhưng trong q trình in ấn cột ký hiệu nhóm bị mờ <tên nhóm> và
khơng đọc được chỉ cịn lại <số thành viên>.
Ví dụ:

hiệu Thành viên
TIN 3
Việt
TOAN 2
Tuấn
TIN 3
Thái
TIN 3
Anh
TOAN 2
Chính

Do lỗi in ấn


hiệu Thành viên
TIN 3
Việt
TOAN 2

Tuấn
TIN 3
Thái
TIN 3
Anh
TOAN 2
Chính

Yêu cầu: Cho danh sách gồm N học sinh và số thành viên của nhóm tương ứng với
từng học sinh. Hãy xác định nhóm đề tài đã được phân công. Dữ liệu đảm bảo bài tốn có
nghiệm.
Ví dụ:

Dữ liệu vào
N=5
3 2 3 3 2
N=10
5 1 2 5 5 2 5 5 2 2

Kết quả
2
3

Mới nhìn, u cầu bài tốn có vẻ khó giải quyết, tuy nhiên, dựa vào ví dụ ta thấy giá trí
có xuất hiện nhiều lần hay một lần thì ta đếm là một đề tài. Vì thế, cách đơn giản để giải quyết
yêu cầu cảu bài này là áp dụng thuật toán "Lùa bị vào chuồng" hồn tồn tương tự như bài 8.
Chỉ khác ở đây là đếm những "chuồng" có giá trị lớn hơn 0 thì số lượng đếm được chính là
nhóm đề tài tìm được.
Thuật tốn được minh họa thơng qua các bước như sau:
GV: Nguyễn Trương Tiên


16

Năm học: 2016-2017


Sáng kiến: ĐẾM ĐƠN GIẢN BẰNG THUẬT TỐN LÙA BỊ VÀO CHUỒNG
-Input: Giá trị N và N giá trị tương ứng, mảng Dem có các giá trị ban đầu đều bằng 0.
-Output: Số lượng nhóm đề tài tìm được.
+B1: Nhập N.
+B2: i←0; Max←0;
+B3: i←i+1; Nếu i>N thì chuyển đến bước 6.
+B4: Nhập giá trị x thứ i; Dem[x]←Dem[x]+1;
+B5: Nếu Max < x thì Max←x; Quay lại bước 3.
+B6: i←0;d←0;
+B7: i←i+1; Nếu i>Max thì chuyển đến bước 9.
+B8: Nếu Dem[i] >0 thì d ←d+1 và quay lại bước 7.
+B9: In giá trị d tìm được và kết thúc thuật tốn.
uses crt;
var Dem:array[1..50]of byte;
N,max:byte; f:text;
procedure kt_docdl;
var i,x:byte;
begin
assign(f,'Nhom_DT.inp');
{$I-} reset(f);{$I+}
if IOResult>0 then
begin
rewrite(f);reset(f);
end;

fillchar(Dem,sizeof(Dem),0);
readln(f,n);max:=0;
for i:=1 to n do
begin
read(f,x);Dem[x]:=Dem[x]+1;
if x>max then max:=x;
end;
close(f);
end;

Chương trình tham khảo
procedure xuly;
var i,d:byte;
begin
assign(f,'Nhom_DT.out');
rewrite(f);
for i:=1 to max do
if dem[i]>0 then
inc(d);
writeln(f,d);
close(f);
end;
begin
kt_docdl;
xuly;
End.

Bài 10: Phủ nhỏ nhất
Tên tệp chương trình: Phu.pas
(Đề thi chọn HSG Quốc gia lớp 12 năm 1998-1999)

Cho tập hợp N đoạn thẳng (đánh số từ 1 đến N) với các đầu mút có tọa độ nguyên
[Li,Ri], i=1,2,3,..,n và một đoạn thẳng [P,Q] (P, Q là các số ngun).
u cầu: Cần tìm một số ít nhất đoạn thẳng trong tập đã cho để phủ kín đoạn thẳng
[P,Q] (nghĩa là mỗi điểm x thuộc [P,Q] phải thuộc vào ít nhất một trong số các đoạn thẳng
được chọn).
Dữ liệu vào: từ file văn bản PHU.INP:
- Dòng đầu tiên ghi 3 số n, P, Q phân cách nhau bởi dấu trắng;
- Dòng thứ i trong số n dòng tiếp theo chứa hai số L, R phân cách nhau bởi dấu trắng
(i=1, 2,…, n); 1 ≤ n ≤ 100 000; P − Q ≤5000; |Li| ≤ 50000; |Ri|≤50000, i = 1, 2,…, n.
GV: Nguyễn Trương Tiên

17

Năm học: 2016-2017


Sáng kiến: ĐẾM ĐƠN GIẢN BẰNG THUẬT TỐN LÙA BỊ VÀO CHUỒNG
Kết quả: ghi ra file văn bản PHU.OUT:
- Dòng đầu tiên ghi số k là số lượng đoạn cần chọn (quy ước ghi số 0 nếu khơng tìm
được lời giải);
- Nếu k > 0 thì mỗi dịng trong số k dòng tiếp theo ghi số của một đoạn thẳng được
chọn.
Ví dụ:
Phu.INP
Phu.OUT
2 0 1
1
-1 0
2
0 1

Thuật tốn: Ta phân tích bài tốn để có thể áp dụng sáng tạo tư tưởng của thuật tốn đã
trình bày như sau: Ta thấy rằng độ dài đoạn thẳng [P,Q] không lớn hơn 5000. Cịn số đoạn
thẳng trong tập đã cho có thể lên tới 100000. Ta không thể lưu tất cả các đoạn thẳng này lại
được. Vậy chúng ta có thể lưu các đoạn thẳng này theo cách: lưu từng đoạn một, dùng một
mảng A có độ dài chính bằng độ dài đoạn thẳng [P,Q], kích thước của mảng này là 5000x2
(A: Array [ 0..5000, 1..2 ] Of LongInt;)
Ta coi đoạn [P,Q] là mảng A trên. Ta lần lượt đọc các đoạn thẳng của tập n các đoạn
thẳng. Với mỗi đoạn thẳng vừa đọc được, ta xét xem chúng phủ đoạn [P,Q] bắt đầu từ đâu và
độ dài mà đoạn thẳng đó phủ được. Ta sẽ lưu lại trên mảng A ở phần tử mà đoạn thẳng chúng
ta vừa đọc bắt đầu phủ đoạn [P,Q] chỉ số của đoạn thẳng đó và độ dài chúng phủ được.
A[Phần tử bắt đầu phủ,1] = chỉ số của đoạn vừa đọc và A[Phần tử bắt đầu phủ, 2]=
độ dài mà đoạn đó phủ được.
Nếu có nhiều đoạn thẳng bắt đầu phủ đoạn [P,Q] tại cùng một vị trí thì chọn đoạn nào có
độ dài phủ được là lớn nhất.
Sau khi làm xong công việc trên ta được một mảng gồm các đoạn thẳng phủ lên đoạn
[P,Q]. Bây giờ ta sẽ tiến hành tìm xem số đoạn phủ ít nhất sẽ là bao nhiêu bằng cách: ta bắt
đầu đi từ vị trí 0 (nếu tại vị trí này mà khơng có đoạn nào phủ thì sẽ khơng có lời giải) ta tìm
xem có đoạn nào giao với đoạn này mà tạo thành một đoạn thẳng có phủ dài nhất thì ta lưu
đoạn này lại (nếu khơng có đoạn thẳng nào giao với đoạn thẳng này để tạo được một đoạn
thẳng có độ che phủ lớn hơn độ che phủ của đoạn trên thì sẽ khơng có lời giải). Làm tương tự
với đoạn thẳng vừa tìm được cho đến khi các đoạn thẳng được chọn sẽ phủ kín đoạn [P,Q] ta
sẽ được số đoạn thẳng ít nhất để phủ đoạn [P,Q]. Như vậy, thuật toán này cho phép giải quyết
bài toán cũng chỉ với một lần duyệt mảng duy nhất.
Chương trình tham khảo
Const Fi = ′PHU.INP′; Fo = ′PHU.OUT′;
Procedure xuly;
Max = 5000; Dd = 2;
Var i,j,tmp,Count,Max:LongInt;
Type Vec1 = Array [ 0..Max,1..2 ] Of LongInt;
Dung:Boolean;

Vec2=Array[0..Max] Of LongInt;
Begin
Var n, P, Q, Min,Id : LongInt;
Min:=0;
A : Vec1; Chon : Vec2;
If A[0,id]=0 Then Exit;
Procedure Khoitao_dl;
j:=0;
Var i, L, R : LongInt; F : Text;
Dung:=False;
GV: Nguyễn Trương Tiên

18

Năm học: 2016-2017


Sáng kiến: ĐẾM ĐƠN GIẢN BẰNG THUẬT TỐN LÙA BỊ VÀO CHUỒNG
Begin
Count:=1;
Id:=1; Assign(F, Fi); {$I-}Reset(F); {$I+}
Chon[1]:=A[0,id];
if IOResult>o then
If A[0, Dd] = Q-P Then
begin
Begin
Rewrite(f);reset(f);
Min:=1; Exit;
end;
End;

Readln(F,n,P,Q);
While Not Dung Do
FillChar(A, SizeOf(A),0);
Begin
For i := 1 To n Do
Max:=j+A[j,Dd];
Begin
For i:=j + 1 To j + A[j,Dd] Do
Readln(F,L,R);
If (A[i, id]<>0) And (tt(i, j)>Max)
If L <= P Then
Then
If A[0, Dd] < R - P Then
Begin
Begin
Max:=tinh_toan(i,j); tmp:=i;
A[0, id] := i;
End;
If R > Q Then A[0, Dd] := Q - P
If Max=j+A[j,Dd] Then Exit
Else A[0, Dd] := R - P;
Else
End
Begin
Else If L <= Q Then
Count:=Count + 1;
If A[L - P, Dd] < R - L Then
Chon[Count]:=A[tmp, id];
Begin
j:=tmp;

A[L - P, id] := i;
If Max = Q - P Then
If R > Q Then
Dung := True;
A[L - P, Dd] := Q - L
End;
Else A[L - P, Dd] := R - L;
End;
End;
Min := Count;
End;
End;
Close(F);
Procedure IN_KQ;
End;
Var F : Text; i : LongInt;
Function tinh_toan(u,v:LongInt):LongInt;
Begin
Begin
Assign(F, FO); ReWrite(F);
If A[u, Dd]+u<=A[v,Dd]+v Then tt:=A[v,Dd]+v
Writeln(F, Min);
Else tt:=A[u,Dd]+u;
If Min <> 0 Then
End;
For i: = 1 To Min Do Writeln(F,
Chon[i]); Close(F);
End;
Begin
Khoitao_dl;

xuly;
IN_KQ;
End.
2.4. Kết quả thực hiện
Nếu biết vận dụng tốt những suy luận sẽ làm cho những bài tốn Tin học có những
giải thuật đơn giản và đạt được kết quả tốt hơn. Đặc biệt là trong cơng việc đếm, địi hỏi phải
lựa chọn cách giải quyết phù hợp cho các bài tốn có đầu vào lớn.
Qua q trình nghiên cứu và vận dụng đề tài “ĐẼM ĐƠN GIẢN BẰNG THUẬT
TOÁN LÙA BỊ VÀO CHUỒNG”, tơi nhận thấy vấn đề này giúp ích rất nhiều cho học sinh
GV: Nguyễn Trương Tiên

19

Năm học: 2016-2017


Sáng kiến: ĐẾM ĐƠN GIẢN BẰNG THUẬT TỐN LÙA BỊ VÀO CHUỒNG
chuyên Tin trong việc học, giúp các em không còn “ngán ngại” chuyên đề này nữa, các em đã
hiểu và vận dụng khá tốt những phần liên quan đến việc đếm ứng dụng vào Tin học; một số
em đã bước đầu sáng tạo được những cách giải hay, các giải mới (tuy là những bài tốn cịn
“đơn giản”), giúp giáo viên vận dụng để giải quyết một số bài tốn Tin liên quan. Riêng 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 hy vọng sẽ “làm rõ hơn nữa” để
học sinh chuyên Tin thích học và đạt nhiều thành tích hơn nữa.
Qua việc nghiên cứu và vận dụng sáng kiến vào quá trình bồi dưỡng học sinh giỏi
cấp trường, cấp huyện cũng như sự áp dụng của một số giáo viên Tin trong huyện. Số lượng
và chất lượng giải khi học sinh tham gia dự thi cấp huyện, cấp tỉnh ngày càng tăng lên, nhất là
chất lượng giải của đội tuyển dự thi học sinh giỏi cấp tỉnh năm học 2015-2016 và kết quả học
sinh giỏi cấp tỉnh năm học vừa qua (3/4 HS đạt giải: 1 nhất, 1 nhì, 1 ba).
3. Kết luận và kiến nghị
3.1. Những kết luận đánh giá cơ bản nhất về sáng kiến:

Tôi viết đề tài nghiên cứu này nhằm mục đích cùng trao đổi với Quý Thầy Cô dạy
chuyên đề bồi dưỡng học sinh giỏi Tin học về việc “hệ thống” các kiến thức, một vài kỹ năng,
ứng dụng tốn học vào lập trình giải quyết các bài tốn Tin học trong chủ đề "đếm". Nó có ý
nghĩa rất quan trọng cho học sinh tham gia bồi dưỡng học sinh giỏi cấp huyện, cấp tỉnh. Bởi
vì khi đã tiếp xúc và làm quen các dạng bài toán tin này, học sinh sẽ khơng cịn "ngán ngại"
đến chủ đề đã tìm hiểu, giúp nhiều học sinh hình thành kỹ năng giải các bài toán Tin với dữ
liệu đầu vào lớn, tối ưu về thuật toán, về thời gian thực hiện chương trình trên máy tính. Cũng
như việc hình thành kỹ năng giải quyết các bài toán Tin liên quan khác đối với học sinh và
giáo viên.
Vì kiến thức và thời gian còn nhiều hạn chế nên chắc rằng nghiên cứu cịn có thiếu
sót, tơi chân thành đón nhận sự góp ý của Q Thầy Cơ. Xin chân thành cảm ơn.
3.2. Các đề xuất kiến nghị:
- Phổ biến đại trà cho tất cả các giáo viên và học sinh tham gia bồi dưỡng học sinh
giỏi tất cả các huyện trong tỉnh để nhân rộng tính khả thi áp dụng của đề tài.
- Bổ sung, cung cấp thêm các tài liệu nói đến dạng bài tập liên quan đến đề tài đang
nghiên cứu để làm thêm tính phong phú của thuật tốn "Lùa bị vào chuồng".
Tài liệu tham khảo
1. Hồ Sĩ Đàm, Đỗ Đức Đơng, Lê Minh Hồng, Nguyễn Thanh Hùng, 2009, Tài liệu

giáo khoa chuyên tin, NXB Giáo dục, quyển 1, quyển 2, quyển 3.
2. Nguyễn Xuân Huy, 2008, Sáng tạo trong thuật tốn và lập trình, NXB Giáo dục,

tập 1, tập 2, tập 3.
3. Mạng Internet.

GV: Nguyễn Trương Tiên

20

Năm học: 2016-2017



Sáng kiến: ĐẾM ĐƠN GIẢN BẰNG THUẬT TỐN LÙA BỊ VÀO CHUỒNG
MỤC LỤC
1. Đặt vấn đề.....................................................................................................................1
1.1. Lý do chọn đề tài....................................................................................................1
1.2. Xác định mục đích nghiên cứu...............................................................................1
1.3. Đối tượng nghiên cứu.............................................................................................1
1.4. Đối tượng khảo sát, thực nghiệm............................................................................1
1.5. Các phương pháp nghiên cứu.................................................................................2
1.6. Phạm vi và thời gian nghiên cứu............................................................................2
2. Nội dung....................................................................................................................... 2
2.1.Cơ sở lý luận của đề tài............................................................................................2
2.2.Thực trạng của vấn đề nghiên cứu...........................................................................2
2.3. Mơ tả, phân tích các giải pháp................................................................................2
Bài 1: Đếm bò........................................................................................................... 3
a/ Cách 1: Chưa vận dụng thuật tốn "lùa bị vào chuồng"....................................3
b/ Cách 2: Vận dụng thuật tốn "lùa bị vào chuồng"............................................4
Bài 2: Dự tiệc............................................................................................................ 6
Bài 3: Chuổi kiểm tra................................................................................................8
Bài 4: Số lần xuất hiện của ký tự............................................................................10
Bài 5: Tổng các số khác nhau.................................................................................11
Bài 6: Tuyển nhân viên...........................................................................................12
Bài 7: Tần số...........................................................................................................13
Bài 8: Số nhỏ nhất..................................................................................................14
Bài 9: Số lượng nhóm đề tài...................................................................................16
Bài 10: Phủ nhỏ nhất..............................................................................................17
2.4. Kết quả thực hiện..................................................................................................19
3. Kết luận và kiến nghị..................................................................................................20
3.1. Những kết luận đánh giá cơ bản nhất về sáng kiến...............................................20

3.2. Các đề xuất, kiến nghị..........................................................................................20
Tài liệu tham khảo..........................................................................................................20

GV: Nguyễn Trương Tiên

21

Năm học: 2016-2017


Sáng kiến: ĐẾM ĐƠN GIẢN BẰNG THUẬT TỐN LÙA BỊ VÀO CHUỒNG
Tôi xin cam đoan sáng kiến này là do tơi tìm tịi, trích lọc, nghiên cứu.
Hồi Nhơn, tháng 05 năm 2017
Người viết

Nguyễn Trương Tiên

Xét duyệt công nhận sáng kiến kinh nghiệm cấp Trường
....................................................................................................................................................
....................................................................................................................................................
....................................................................................................................................................
....................................................................................................................................................
....................................................................................................................................................
....................................................................................................................................................
....................................................................................................................................................
....................................................................................................................................................
....................................................................................................................................................
....................................................................................................................................................
Xét duyệt công nhận sáng kiến kinh nghiệm cấp Huyện
....................................................................................................................................................

....................................................................................................................................................
....................................................................................................................................................
....................................................................................................................................................
....................................................................................................................................................
....................................................................................................................................................
....................................................................................................................................................
....................................................................................................................................................
....................................................................................................................................................
....................................................................................................................................................
Xét duyệt công nhận sáng kiến kinh nghiệm cấp Tỉnh
....................................................................................................................................................
....................................................................................................................................................
....................................................................................................................................................
....................................................................................................................................................
....................................................................................................................................................
....................................................................................................................................................
....................................................................................................................................................
....................................................................................................................................................
GV: Nguyễn Trương Tiên

22

Năm học: 2016-2017


Sáng kiến: ĐẾM ĐƠN GIẢN BẰNG THUẬT TỐN LÙA BỊ VÀO CHUỒNG
....................................................................................................................................................
....................................................................................................................................................

GV: Nguyễn Trương Tiên


23

Năm học: 2016-2017



×