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

SỬ DỤNG THUẬT TOÁN ĐẾM PHÂN PHỐI VÀ THUẬT TOÁN SẮP XẾP NHANH

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 (177.64 KB, 29 trang )

I. ĐẶ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 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 1



II. 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 sinh
giỏ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ọc
sinh 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ạt
trong 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 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, 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’’
2. THỰC TRẠNG CỦAVẤN ĐỀ:
Khi học về lập trình TURBO PASCAL đa số học sinh rất khó khăn khi
giải các bài toán phải sử dụng đến thuật toán nâng cao để có được cách giải tối
ưu nhất, các em rất lúng túng trong quá 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ình giải các bài toán.
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 2



mộ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 đế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 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ủ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(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 3



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]])
Bước 3: Duyệt mảng B, tìm chỉ số phần tử lớn nhất.
Chương trình:
Var N: integer;
A: array[1..1000] of byte;
B: array[1..10000] of byte;
slmax, i, csln: integer;
BEGIN
Write('Nhap vao so nguyen duong N = ');
Readln(N);
For i := 1 to N do
Begin
Write('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 4



{Thực hiện lùa bò vào chuồng}
For i := 1 to N do inc (B [A[i] ] );
slmax := 0;
{Duyet day chuong tim ra chuong co nhieu bo nhat}
For i := 1 to max do
if B[i] > slmax then
Begin
slmax := B[i];
csln := i;
End;
Write('So ',csln, ' co tan suat xuat hien nhieu nhat la: ',B[csln]);
Readln;
END.
Bài toán 2: Nhập vào số nguyên dương N (2các phần tử nguyên dương.
Yêu cầu: Cho biết dãy trên có bao nhiêu phần tử khác nhau?
Hướng dẫn:
Để giải bài này ta dùng thuật toán “lùa bò vào chuồng”, Các phần tử bằng
nhau sẽ nhốt chung một chuồng, có bao nhiêu chuồng thì có bấy nhiêu phần tử
khác nhau trong dãy ban đầu.
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 đơ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.
Chương trình:
Trang 5



var

A:array[1..1000] of integer;
B:array[0..32000] of integer;
i, j, n, Dem:integer;

Begin
write('Nhap so phan tu cua day ');
readln(n);
For i := 1 to n do
Begin
Write('A[',i,'] = ');
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 (2cá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 6



- 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);
reset(f);
readln(f,n);
for i:=1 to n do readln(f,a[i]);
close(f);
{khoi tao ban dau day chuong bo chua co bo}
fillchar(b,sizeof(b),0);
{lua bo vao chuong}
for i:=1 to n do inc(b[a[i]]);

assign(f,fr);

Trang 7


rewrite(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ách
viế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ột
lầ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ột
khoả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ớn
hay 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 8


Input.int

Input.out

4

2

2
6
6
3
Chương trình:
Const fv=' input.int’;
fr=' input.out ';
Var A,B : Array[1..1000000] of Int64; N: Int64;
Procedure Input;
Var

f:Text;

i:Longint;

Begin
Assign(f,fv); Reset(f);

Readln(f,N);
Fillchar(B,sizeof(B),0);
For i:=1 to N Do
Begin
readln(f,A[i]);
B[A[i]]:=B[A[i]]+1;
End;
Close(f);
End;
Procedure Output;
Var

f:text;
dem,i:Longint;

Begin
Assign(f,fr); Rewrite(f);
dem:=0;
Trang 9


For i:=1 to N do
If B[A[i]]=1 then dem:=dem+1;
write(f,dem);
Close(f);
End;
BEGIN
Input; Output;
END.
Bài toán 5: Cho trước một dãy số nguyên dương, hãy tìm ra các số lẻ chỉ xuất

hiện một lần.
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<=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

5
1

3

2
2
3
1

Trang 10


Chương trình:
const fv=' baitoan5.int'; fr=' baitoan5.out';
var f:text;
a:array[1..1000] of integer;
b:array[1..10000] of integer;
i,n:integer;

Begin
Assign(f,fv);reset(f);
readln(f,n);
for i:=1 to n do readln(f,a[i]);
close(f);
fillchar(b,sizeof(b),0);
for i:=1 to n do if (a[i] mod 2<>0) then inc(b[a[i]]);
assign(f,fr);
rewrite(f);
for i:=1 to n do if b[i]=1 then
write(f,i,' ');
close(f);
End.
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
quá 255 ký tự
Dữ liệu ra: Ghi ra file văn bản baitoan6.out tần suất xuất hiện của các ký tự.
Chương trình:
const fv=' baitoan6.inp';
fr=' baitoan6.out';
Trang 11


var f:text;
b:array[1..122]of integer;
s:string;
ss,sn,sh:set of byte;
ma,i:integer;

Begin
assign(f,fv); reset(f);
read(f,s);
close(f);
ss:=[65..90]; sn:=[48..57]; sh:=[97..122];
fillchar(b,sizeof(b),0);
for i:=1 to length(s) do
begin
ma:=ord(s[i]); {lay ma ascii}
if (ma in ss) or (ma in sn) or (ma in sh) then
inc(b[ma]);
end;
assign(f,fr);
rewrite(f);
for i:=1 to 122 do
if b[i]<>0 then
writeln(f,'ky tu ',CHR(i),' xuat hien ',b[i],' lan');
close(f);
End.

Trang 12


Bà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
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

Code:
Const fv=' baitoan7.inp;
fr=' baitoan7.out';
var f:text;
a:array[1..122] of byte;
s:string;
i:integer;
ma,csmax,tansuatmax:byte;
BEGIN
assign(f,fv);reset(f);
read(f,s);
close(f);
fillchar(a,sizeof(a),0);
for i:=1 to length(s) do
begin
s[i]:=upcase(s[i]);
ma:=ord(s[i]); {lay ma ascii}
if ma in [65..90] then INC(a[ma]);
Trang 13


end;
assign(f,fr);
rewrite(f);
tansuatmax:=0;
for i:=1 to 122 do
if a[i]>tansuatmax then
begin
tansuatmax:=a[i];
csmax:=i;

end;
write(f,'ky tu ',chr(csmax),' xuat hien nhieu nhat:',tansuatmax,' lan');
close(f);
END.
Bà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.
Code:
Const Max=32000;
fv=' baitoan8.inp;
fr=' baitoan8.out';
M=50;
Var

i, j, n: Integer;
Trang 14


A: Array[1..m] of Integer;
B: Array[1..max] of Boolean;
f:text;
BEGIN
assign(f,fv);
reset(f);
readln(f,n);
for i:=1 to n do
read(f,a[i]);

close(f);
FillChar(B,Sizeof(B),False);
For i:= 1 to max do
for j:=1 to n do
B[A[j]]:= True;
assign(f,fr);
rewrite(f);
For i:=1 to max do
If B[i]=False then
begin
write(f,i,' ');
Break;
end;
close(f);
END.

Trang 15


Thuậ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 con
lạ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 ra
thuậ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ủa
bà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ủa
bài toán A;
End;
End;
Xuất phát từ bài toán: Cho dãy A gồm N số nguyên. Sắp xếp dãy A thành dãy
tăng dần
Bài toán sắp xếp là bài toán quen thuộc và có nhiều thuật toán để giải bài
toán này. Các thuật toán Sắp xếp nổi bọt hay chèn trực tiếp đều có độ phức tạp
cỡ O(n2). Thuật toán sắp xếp nhanh (Quick Sort) với tư tưởng chia để trị, Quick
Sort cho ta độ phức tạp nhỏ hơn thường là O(nlogn).
Trang 16


Thuậ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ơn
hoặ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ục
phân chia các dãy con theo cách tương tự cho đến khi mọi dãy con đều có độ dài
bằ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ên
mộ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 LBước 1: key=(L+R) div 2; K=X[key];
Bước 2: i:=L; j:=R;

Bước 3:
Nếu X[i]Nếu X[j]>K thì giảm j;
Bước 4: Nếu iBướ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] đến
X[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]if i<=j then
begin
Trang 17


tg:=X[i];
X[i]:=X[j];
X[j]:=tg;
inc(i);
dec(j);
end;
until i>j;
if iif j>l then quicksort(l,j);
end;


Bài toán áp dụng:
Bà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ác
bế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ủa
bế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òng
ghi cách nhau bởi một dấu cách.

Ý tưởng:
Để xác định bến thứ i (i:1 – N) có thể chọn hay không ta sẽ tính tổng S
của bến này với hai bến bất kỳ đã chọn và so sánh với Sum – S (Sum là tổng số
xe của tất cả các bến).
Vì vậy, thay vì phải duyệt tất cả các bến ta thực hiện sắp xếp các bến xe
theo thứ tự tăng dần của số lượng xe. Khi đó để xét bến thứ i có thể chọn hay

không ta chỉ cần tính tổng S của bến này với hai bến đứng trước nó trong dãy đã
sắp xếp. Nếu S <= Sum – S thì bến thứ i được chọn. Việc chọn các bến xe sẽ

Trang 18


dừ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.
Xây dựng chương trình:
Const

nmax=100000;
fv=' baitoan7.inp;
fr=' baitoan7.out';

var

a:array[1..nmax]of longint;
n:int64;
procedure
DocDL;
var i:longint;
f:text;
begin
assign(f,fv);
Reset(f);
readln(f,n);
for i:=1 to n do
read(f,a[i]);
Close(f);

end;
procedure
quicksort(l,h:longint);
var i, j, x, tg:longint;
begin
i:=l;
j:=h;
x:=a[(l+h) shr 1];
repeat
while a[i]while a[j]>x do dec(j);
if i<=j then
begin
tg:=a[i];
a[i]:=a[j];
a[j]:=tg;
inc(i);
dec(j);
end;
until i>j;
if j>l then quicksort(l,j);
if iend;
procedure
Xuly;
var i:longint;
sum:int64;
f:text;
begin
assign(f,fr);

rewrite(f);
Trang 19


sum:=0;
for i:=1 to n do
sum:=sum+a[i];
i:=n;
while i>3 do
if (a[i]+a[i-1]+a[i-2])<=(sum shr 1) then break
else dec(i);
write(f,'so xe chon duoc nhieu nhat la: ',i);
Close(f);
end;
BEGIN
DocDL;
quicksort(1,n);
Xuly;
END.
Bà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ách
khá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à v j
đơ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 đi
tham 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 20


-

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 = ∑d n-i+1*vi với i=1,..,n. Chỉ số xe
phục vụ các đoàn là giá trị từ 1 đến n trong dãy ID.

Xây dựng chương trình
const

fv=' baitoan7.inp;
fr=' baitoan7.out';

Type mang=array[1..10000] of integer;
var d, v, id:mang;
n, m:integer;
min:longint;
procedure
docdulieu;
var i:longint; f:text;
begin
assign(f,fv); reset(f);
fillchar(id,sizeof(id),0);
readln(f,m,n);
for i:=1 to n do
readln(f,d[i]);
readln(f);
for i:=1 to m do
begin

readln(f,v[i]);
id[i]:=i;
end;
close(f);
end;
procedure quicksort(l,h:integer);
var i,j,key,tg,tg1:integer;
begin
i:=l;
j:=h;
key:=v[(l+h) div 2];
repeat
while v[i]while v[j]>key do dec(j);
if i<=j then
begin
tg:=v[i];
v[i]:=v[j];
Trang 21


v[j]:=tg;
tg1:=id[i];
id[i]:=id[j];
id[j]:=tg1;
inc(i);
dec(j);
end;
until i>j;
if j>l then quicksort(l,j);

if iend;
procedure quicksort2(l,h:integer);
var i,j,key,tg:integer;
begin
i:=l;
j:=h;
key:=d[(l+h) div 2];
repeat
while d[i]>key do inc(i);
while d[j]if i<=j then
begin
tg:=d[i];
d[i]:=d[j];
d[j]:=tg;
inc(i);
dec(j);
end;
until i>j;
if j>l then quicksort(l,j);
if iend;
procedure
Xuly;
var i:integer;f:text;
Begin
QuickSort(1,m);
QuickSort2(1,n);
min:=0;

for i:=1 to n do min:=min+v[i]*d[i];
assign(f,fr); rewrite(f);
writeln(f,min);
for i:=1 to n do Write(f, id[i]);
close(f);
end;
Trang 22


Begin
docdulieu;
Xuly;
end.
Bài toán 3:
Nhân dịp đầu năm mới, công viên trung tâm tổ chức trò chơi “con số may
mắn”. Mỗi em nhỏ đến tham dự sẽ được phát một số nguyên dương. Công viên
có một thiết bị quay số, mỗi lần quay sẽ tạo ngẫu nhiên một số nguyên dương có
giá trị tuyệt đối không vượt quá 10 4. Người dẫn chương trình sẽ thực hiện N lần
quay số. Số nào xuất hiện nhiều nhất trong N lần quay được gọi là con số may
mắn và em nhỏ nào có con số may mắn thì sẽ được phần thưởng.
Yê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.
Ví dụ:

Baitoan3.inp Baitoan3.out Baitoan3.inp


Baitoan3.out

5

2

3

7

4 3 4 4 15

12 5 10 5 8 10
9

Ý tưởng:
-

Sắp xếp dãy theo chiều tăng dần

-

Max:=0;

-

Đếm các phần tử cạnh nhau và bằng nhau, tìm số lượng phần tử nhiều
nhất:
i:=1;

Trang 23


repeat
d:=1;
while a[i]=a[i+1] do
begin inc(d); inc(i); end;
if d > max then Max:=d;
inc(i);
until i > n;
-

Đưa ra max.

Xây dựng chương trình:
const
Type mang1c=array[1..1000] of integer;
fv=' baitoan7.inp;
fr=' baitoan7.out';
var

a:mang1c;
n,i:integer;
procedure
docdulieu;
var i:integer;
f:text;
begin
assign(f,fv);reset(f);
readln(f,n);

for i:=1 to n do
readln(f,a[i]);
close(f);
end;
procedure quicksort(l,h:integer);
var i,j,key,tg:integer;
begin
i:=l;
j:=h;
key:=a[(l+h) div 2];
repeat
while a[i]while a[j]>key do dec(j);
if i<=j then
begin
tg:=a[i];
a[i]:=a[j];
a[j]:=tg;
Trang 24


inc(i);
dec(j);
end;
until i>j;
if j>l then quicksort(l,j);
if iend;
procedure
xuly;

var i,d:integer;f:text;
Begin
quicksort(1,n);
for i:=1 to n do
if a[i]<>a[i+1] then
inc(d);
assign(f,fr); rewrite(f);
write(f,d);
close(f);
end;
Begin
nhapdulieu;
xuly;
end.

Trang 25


×