Tải bản đầy đủ (.docx) (37 trang)

ung dung kieu xau de giai cac bai toan so

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 (160.3 KB, 37 trang )

TÓM TẮT NỘI DUNG SÁNG KIẾN
Đặt vấn đề: Môn Tin học đã được đưa vào giảng dạy chính thức trong
chương trình bậc học trung học phổ thông. Lập trình là một chủ đề khó trong
chương trình Tin học ở bậc phổ thông. Lượng thời gian 1.5 tiết/tuần chỉ giúp học
sinh biết sử dụng ngôn ngữ lập trình Pascal để viết chương trình giải bài toán
trên máy tính. Để giải một bài toán trên máy tính ngoài việc nắm vững ngôn ngữ
lập trình, tư duy toán học đòi hỏi học sinh phải có sự sáng tạo để giải được
những bài toán phức tạp. Cái khó ở đây không phải là ngôn ngữ mà là thuật toán.
Thế nhưng có thuật toán rồi việc cài đặt thuật toán đó như thế nào là cả một vấn
đề. Trong các kì thi học sinh giỏi Tỉnh thì Môn Tin học là thi lập trình giải các
bài toán trên máy tính. Trong đó tập trung là dạng bài toán số. Có những bài toán
số nếu ta biết kết hợp sử dụng kiểu dữ liệu xâu để giải thì việc tìm ra Output đơn
giản hơn nhiều. Trong quá trình giảng dạy cho học sinh lớp 11 Toán, 11 Hóa, 11
Tin và bồi dưỡng học sinh giỏi, học hỏi đồng nghiệp và nghiên cứu một số sách
tham khảo tôi đã tìm ra một cách tiếp cận để giải được các bài toán số học nhờ
sử dụng kiểu dữ liệu xâu. Việc sử dụng kiểu dữ liệu xâu giúp cho một số bài toán
được lập trình giải trên máy tính trở nên đơn giản, thuận lợi hơn nhiều. Thông
qua một số bài tập số học nhờ sử dụng kiểu dữ liệu xâu học sinh mới thấy được
lợi ích và cái hay của kiểu dữ liệu xâu.
Ví dụ : Viết chương trình nhập vào số tự nhiên n(0tổng các chữ số của n?
Để giải bài toán trên các em học sinh sẽ sử dụng hai phép toán div và mod
để tìm ra được các chữ số của n và đem cộng lại để được tổng.
Đoạn mã chương trình
Program viduc1;
var n,t:longint;
1


Begin
readln(n); t≔0;


while n>0 do
begin
t≔t+n mod 10;

n≔n div 10;

end;
writeln(t);
End.
Đánh giá:
-Với cách viết trên ta phải sử dụng n lần hai phép toán chia nguyên và chia
lấy phần dư. Như vậy sẽ mất nhiều thời gian thực hiện chương trình.
-Tối đa n mới nhận được 2.10 9, còn lớn hơn trong Free Pascal thì tối đa
được n mới được 2.1018 . Mà đề bài cho 0Do vậy để tính tổng các chữ số của n với 0kí tự thì việc khai báo không lo tràn số và để tính tổng các chữ số của n ta chỉ
cần sử dụng một vòng lặp for duyệt lần lượt từng kí tự, với mỗi kí tự ta lấy mã
của nó trừ đi 48 là ra giá trị của chữ số rồi tính tổng. Cách tính tổng các chữ số
đơn giản rất nhiều. Tiết kiệm thời gian thực hiện chương trình.
Ví dụ với n=142; mã của ‘1’ là 49, để có giá trị là 1 ta lấy mã của ‘1’ rồi
trừ 48
Để lấy mã của kí tự ‘1’ ta sử dụng hàm ord(‘1’) => cho kết quả là 49 ta trừ
đi 48 sẽ được 1. Như vây n=142 ta sẽ tính được tổng 1+4+2=7.
Đoạn mã chương trình đầy đủ:
Program viduc2;
var n:string;

i,t:longint;
2



Begin
readln(n);
for i:=1 to length(n) do t:=t+ord(s[i])-48;
writeln(t);
End.
Như vậy với bài toán trên ta thấy được lợi ích của kiểu dữ liệu xâu đã giúp
cho việc giải bài toán đơn giản rất nhiều. Hiệu quả cả về thời gian thực hiện
chương trình và bộ nhớ lưu trữ dữ liệu.
Với kinh nghiệm giảng dạy nhiều năm dạy học tôi đã gợi niềm đam mê,
truyền lửa cho các em thấy được cái hay, cái lợi ích của Lập trình giải các bài
toán trên máy tính. Khi tốt nghiệp phổ thông rất nhiều em đã lựa chọn thi vào
các trường Đại học Bách khoa, Đại học FPT, Đại học Quốc gia các ngành khoa
học kĩ thuật nhất là Ngành Công nghệ thông tin. Việc nắm vững kiến thức Tin
học ở bậc phổ thông sẽ là tiền đề vững chắc giúp các em học tập, nghiên cứu
khoa học thuận lợi hơn rất nhiều. Hiện nay ngành Công nghệ thông tin vẫn là
“hot” trong lĩnh vực xin việc và thu nhập cao. Để có được sự thành công của
các em ngoài niềm say mê, quyết tâm phấn đấu của các em, bên cạnh đó cũng có
những tiền đề mà thấy cô đã nhóm lửa cho các em yêu thích. Do vậy tôi viết
chuyên đề này để chia sẻ với các đồng nghiệp để các thầy cô cùng tham khảo và
đóng góp ý kiến.

3


PHẦN 2:MÔ TẢ SÁNG KIẾN
2.1. QUY TRÌNH GIẢI MỘT BÀI TOÁN
Để giải được các bài toán số nhờ kiểu dữ liệu xâu thì học sinh phải thông
hiểu các hàm và thủ tục trong xâu kí tự. Trong sách giáo khoa chương trình tin
học 11 có trình bày một số hàm và thủ tục trong xâu nhưng chưa đủ để giải quyết

một số bài tập thường gặp. Sau đây tôi xin trình bày tóm tắt lại một số hàm và
thủ tục chuẩn trong xâu và bổ sung thêm một số hàm, thủ tục chuẩn trong kiểu
dữ liệu xâu.
- Delete(s,vt,n); Dùng để xóa n kí tự trong xâu s bắt đầu từ vị trí vt.
- Insert(s1,s2,vt); Dùng để chèn xâu s1 và xâu s2 bắt đầu từ vị trí vt.
- Copy(s,vt,n); Hàm tạo ra xâu gồm n kí tự liên tiếp bắt đầu từ vị trí vt
trong xâu s.
- Length(s); Hàm cho giá trị là độ dài của xâu s.
- Pos(s1,s2); Hàm cho vị trí xuất hiện đầu tiên của xâu s1 trong xâu s2.
- Upcase(ch); Hàm cho chữ cái in hoa ứng với chữ cái trong ch.
- Val(s,x,code); Dùng để đổi xâu s thành một số và gán cho x.
- Str(x,s); Dùng để đổi số x thành xâu s.
- Ord(ch); Hàm cho biết mã của kí tự ch.
* Quy tắc so sánh xâu: Xâu A lớn hơn xâu B nếu như kí tự đầu tiên khác
nhau giữa chúng kể từ trái sang trong xâu A có mã ASCII lớn hơn.
Như vậy để giải được các bài toán số nhờ sử dụng kiểu dữ liệu xâu việc
đầu tiên các em cần nắm vững kiến thức lí thuyết kiểu dữ liệu xâu, các hàm và
thủ tục chuẩn trong xâu.
Thứ hai vận dụng thành thạo các hàm và thủ tục chuẩn trong xâu.
Thứ ba biết phân tích, lựa chọn thuật toán sao cho hiệu quả nhất.
4


Bài tập : Cho một số nguyên dương n (0k chữ số sao cho số còn lại sau khi xóa được giá trị là lớn nhất?
Dữ liệu đọc vào từ bàn phím gồm hai số nguyên dương n và k.
Kết quả ghi ra màn hình là giá trị lớn nhất tìm được sau khi xóa đi k chữ
số.
Ví dụ minh họa
Dữ liệu nhập

297683421 4
987654321 3

Dữ liệu in ra
98421
987654

Giải thích
xóa đi 4 chữ số là 2, 7, 6, 3
xóa đi 3 chữ số là 1, 2, 3

Cách tiếp cận dạng số học các em sẽ phải dùng một mảng a để chứa các
chữ số của n. Sau đó so sánh các phần tử trong mảng a để xem những phần tử
nào trong mảng cần phải xóa. Mỗi lần xóa một phần tử thứ i trong mảng a ta phải
dịch chuyển lại các vị trí của phần tử sau phần tử bị xóa một đơn vị là 1.
Đoạn mã chương trình
type mang=array[1..1000000000] of integer;
var a,b:mang;
x,dem,m,i,n,k:longint;
procedure pop( var b: mang; i:integer); // xóa đi phần tử thứ i trong mảng
var j:integer;
begin
for j:=i to m-1 do a[j]:=a[j+1];
end;
begin
readln(n,k);
i:=0;
5



while (n>0) do
begin
i:=i+1;
b[i]:=n mod 10;
n:=n div 10;
end;
m:=i; x:=m;
for i:=1 to m do a[i]:=b[m-i+1]; a[m+1]:=0;
i:=1;
repeat
begin
while (a[i]>=a[i+1]) and (ipop(a,i); // xóa phần tử thứ i trong mảng a
dem:=dem+1; // đếm số lần xóa
m:=m-1; //giảm số phần tử của mảng a
if dem=k then break;
end;
until (dem=k)or (i=m);
for i:=1 to x-k do write(a[i]); // in ra kết quả cần tìm.
readln;
end.

6


Đánh giá :
Với cách tiếp cận như trên, việc giải bài toán rất khó khăn, không phải em
nào cũng xét được hết tất cả các trường hợp đặc biệt nên dễ bị mất điểm.
Thứ hai để xóa một phần tử ở vị trí i nào đó trong mảng kéo theo các phần
tử sau i phải dịch chuyển sang trái một đơn vị do vậy mất thời gian rất nhiều.

Thứ ba mảng a chỉ khai báo kích thước tối đa 10 9 như vậy tối đa n chỉ có
109 chữ số trong khi đề bài cho n≤10200 .
Như vậy chương trình cài đặt như trên không tối ưu vì thời gian thực hiện
chương trình lớn, không đáp ứng được với n lớn.
Cải tiến chương trình: Để xóa đi k lần trong kiểu dữ liệu xâu có thủ tục
xóa delete(s,vt,n) rất thuận lợi. Như vậy thuật toán sẽ tiến hành xóa đi những
chữ số mà chữ số bị xóa phải nhỏ hơn chữ số đứng sau nó thì ta mới thu được số
sau khi xóa là lớn nhất. Vậy để xóa k chữ số ta sẽ làm như sau: Thực hiện xóa k
lần mỗi lần xóa đi một chữ số mà chữ số đó nhỏ hơn số đứng sau. Nếu không có
số nào đứng sau nó lớn hơn thì xóa đi chữ số cuối cùng.
Hơn nữa số nguyên dương n không có kiểu số nguyên nào trong Turbo
pascal hay Free Pascal khai báo được tối đa 10 200 nên phải sử dụng kiểu dữ liệu
xâu để xử lí.
Để thuận tiện khi làm việc với kiểu dữ liệu xâu ta sử dụng biến xâu là s
thay cho n
Đoạn mã chương trình đầy đủ.
program giatrimax;
var s:string;
k,i:longint;
procedure xoa;
begin
7


i:=0;
repeat
inc(i);
until i=(length(s)) or (s[i]delete(s,i,1);
end;

Begin
read(s);
read(k);
for i:=1to k do xoa;
write(s);
readln;
End.
Như vậy nhìn vào chương trình trên chúng ta thấy ngay được hiệu quả của
kiểu dữ liệu xâu để xử lí bài toán số.

2.2. ỨNG DỤNG CỦA KIỂU DỮ LIỆU XÂU ĐỂ GIẢI CÁC BÀI
TOÁN SỐ
Sau đây tôi xin đưa ra một lớp các bài tập số học được giải nhờ sử dụng
kiểu dữ liệu xâu.
Bài tập 1.(Bài 7.40 sách bài tập Tin hoc 11)
Cho số nguyên n người ta tạo ra số nguyên n1 bằng cách viết liên tiếp
nhau các số nguyên từ 1 đến n. Ví dụ với n=11 ta có n1=1234567891011 người
ta thu gọn n1 bằng cách lần lượt xóa tất cả các chữ số ở vị trí chẵn, sau đó xóa tất
cả các chữ số ở vị trí lẻ, rồi lại xóa các chữ số ở vị trí chẵn cho đến khi chỉ còn
lại một chữ số.
Ví dụ: 1234567891011->1357901->370->30->0
Thuật toán:
8


Bước 1: Việc đầu tiên ta phải tạo ra số nguyên n1 từ n bằng cách sử dụng
vòng lặp for duyệt từ i=1 đến n . Với mỗi giá trị của i ta đổi sang xâu và dùng
phép ghép xâu để ghép lại với nhau ta được một xâu s chính là n1.
Bước 2: Ta tiến hành xóa ở các vị trí chẵn trước nên khởi tạo i=2; sau khi
xóa lần thứ nhất một kí tự thì các kí tự ở phía sau vị trí xóa sẽ dịch chuyển sang

bên trái 1 vị trí do vậy i chỉ cần tăng thêm 1 đơn vị. Quá trình xóa lại tiếp tục cứ
như vậy cho đến khi kết thúc nếu i>length(n1);
Bước 3: Tiếp theo tiến hành xóa ở các vị trí lẻ. Khởi tạo i=1, sau khi xóa
lần thứ nhất một kí tự thì các kí tự ở phía sau vị trí xóa sẽ dịch chuyển sang bên
trái 1 vị trí do vậy i chỉ cần tăng thêm 1 đơn vị. Quá trình xóa lại tiếp tục cứ như
vậy cho đến khi kết thúc nếu i>length(n1);
Quá trình xóa vị trí chẵn rồi lại lẻ cứ như vậy cho đến khi n1 chỉ còn một
chữ số. Do vậy bước 2 và bước 3 sẽ lặp đi lặp lại cho đến khi độ dài của n1 bằng
1 thì dừng lại.
Đoạn mã chương trình đầy đủ:
program bt1;
var n,i:longint;
n1,s:string;
Begin
readln(n);
n1:='';
for i:=1 to n do
begin
str(i,s);
n1:=n1+s;
end;
repeat
9


i:=2;
while length(n1)>1 do
begin
delete(n1,i,1);
inc(i);

if i >length(n1) then break;
end;
i:=1;
while length(n1)>1 do
begin
delete(n1,i,1);
inc(i);
if i >length(n1) then break;
end;
until

length(s)=1;

write(s);
readln;
End.
Bài tập 2.
Viết liên tiếp các số nguyên từ 1 đến n thành một dãy các kí tự (n<50). Hỏi
vị trí thứ k là chữ số mấy? Ví dụ n=15, k=12 ta có 123456789101112131415, vị
trí thứ 12 là số 1.
Thuật toán: Để biết ví trí thứ k là chữ số nào việc đầu tiên ta phải tạo được
xâu s chứa các số nguyên liệt kê từ 1 đến n. Sau đó ta in ra s[k] chính là chữ số
cần tìm.
Đoạn mã chương trình đầy đủ:
program bt2;
10


var n,k:longint;
s:string;

Begin
readln(n,k);
s:=‘’;
for i:=1 to n do
begin
str(i,a);
s:=s+a;
end;
writeln(s[k]);
End.
Bài tập 3.
Cho một số nguyên dương n (0trong số nguyên n sao cho các chữ số còn lại sau khi xóa được giá trị là bé nhất?
Ví dụ s=123456789 hãy xóa đi 3 chữ số bất kì để được số bé nhất là :
123456. với s=297683421 k=3 ta được số bé nhất là 263421.
Dữ liệu đọc vào từ file nmin.inp gồm hai số nguyên dương n và k.
Kết quả ghi file nmin.out là giá trị bé nhất tìm được sau khi xóa đi k chữ
số.
Ví dụ:
nmin.inp
4

nmin.out
9056124123

123 56 90 124
Thuật toán : Chúng ta sẽ xóa đi chữ số đầu tiên là chữ số xét từ trái sang
phải chữ số đó lớn hơn chữ số đứng ngay liền sau nó. Quá trình tìm và xóa lại
11



tiếp tục. Như vậy ta tiến hành xóa đi k chữ số như sau: Thực hiện xóa k lần mỗi
lần xóa đi 1 chữ số mà chữ số đó lớn hơn số đứng sau. Nếu không có xóa đi chữ
số cuối cùng.
Đoạn mã chương trình đầy đủ:
program bt3;
const tfi=’nmin.inp’;
tfo=’nmin.out’;
var k,i:longint;
n:string;
procedure xoa;
begin
i:=0;
repeat
inc(i);
until i=(length(s)) or (s[i]>s[i+1]);
delete(s,i,1);
end;
begin
assign(input,tfi);
reset(input);
assign(output,tfo);
rewrite(output);
readln(s);
read(k);
for i:=1to k do xoa;
write(s);
close (input);
close(output);
12



end.
Bài tập 4 (Bài 7.39 –sách bài tập Tin học 11)
Một số nguyên n ở hệ thập phân có chữ số cuối cùng là số chẵn thì sẽ chia
hết cho 2, nếu tổng các chữ số của n chia hết cho 3 thì n sẽ chia hết cho 3.Cho số
nguyên thập phân n không quá 60 chữ số. Hãy xác định xem n có chia hết cho 6
hay không và đưa ra màn hình kết quả kiểm tra ‘Co’ hoặc ‘Khong’ .
Thuật toán: Để kiểm tra xem n có chia hết cho 6 hay không. Trước tiên các
em đều biết 6=2.3. Do vậy n chia hết cho 6 khi n phải là số chẵn và tổng các chữ
số của n phải chia hết cho 3. Vậy việc đầu tiên ta tính tổng các chữ số của n rất
đơn giản bằng cách sử dụng kiểu dữ liệu xâu, sau đó lấy mã của các chữ số của n
rồi trừ cho 48 ta được giá trị tổng các chữ số của n. n chẵn khi chữ số hàng đơn
vị là chẵn do vậy chỉ cần kiểm tra chữ số hàng đơn vị của n chia 2 mà dư 0 là
được.
Đoạn mã chương trình đầy đủ:
program bt4;
var n:string;
m,s,i:longint;
begin
read(n);
m:=length(n);
s:=0;
for i:=1 to m do

s:=s+ord(n[i])-48;

if ((ord(n[m])-48) mod 2=0) and (s mod 3=0)
then write('Co')


else write('Khong');

end.
Bài tập 5: Độ lệch(HSGT vòng 1 năm 2012)
Xét một số N có 4 chữ số và không phải tất cả các chữ số đều giống nhau.
13


Phép tính độ lệch được thực hiện như sau:
• Tạo số thứ nhất N1 bằng cách xếp các chữ số theo trình tự giảm dần.
• Tạo số thứ hai N2 bằng cách xếp các chữ số theo trình tự tăng dần (nếu có
chữ số 0 ởđầu thì N2 sẽ không phải là số có 4 chữ số).
• Tính hiệu N1-N2 và gán lại cho N.
Các bước trên được thực hiện cho đến khi nhận được số N là 6174 hoặc 0.
Ví dụ: Nếu N=1023.
• Ở bước 1: N1=3210, N2=123, N=N1-N2=3087.
• Ở bước 2: N1=8730, N2=378, N=N1-N2=8352.
• Ở bước 3: N1=8532, N2=2358, N=N1-N2=6174.
Vậy ta cần thực hiện 3 lần biến đổi.
Yêu cầu: Hãy xác định số lần biến đổi thực hiện theo yêu cầu trên.
Dữ liệu: Nhập từ bàn phím số nguyên dương N (N đảm bảo có 4 chữ số,
không phải tất cả các chữ số đều giống nhau và N khác 6174. Không cần kiểm
tra dữ liệu nhập).
Kết quả: Ghi ra màn hình số lần biến đổi tương ứng với số N.
Ví dụ:
DEV.INP
5364

DEV.OUT
3


Thuật toán: Thông qua ví dụ trên ta thấy ngay việc đầu tiên phải sắp xếp
các chữ số của N theo thứ tự tăng dần để được số nhỏ nhất. Sau đó lại sắp xếp
các chữ số của N theo thứ tự giảm dần để được số lớn nhất. Rồi đi tính hiệu hai
số lớn nhất và nhỏ nhất. Quá trình sắp xếp lại tiếp tục cứ nhứ vậy cho đến khi
N=0 hoặc N=6174 thì kết thúc quá trình biến đổi.

14


Ta thấy muốn sắp xếp được các chữ số của N là tăng dần hoặc giảm dần
ta sẽ sử dụng thủ tục str(N,s); để đổi N thành xâu s.
Sau đó sắp xếp các kí tự trong xâu s theo thứ tự tăng dần, và một xâu s các
kí tự sắp xếp theo thứ tự giảm dần. Sau khi sắp xếp xong ta sẽ dùng thủ tục đổi
xâu sang số và lấy 2 giá trị đó trừ cho nhau và quá trình lại tiếp tục cho đến khi
N=6174 hoặc N=0 thì dừng lại. Mỗi lần thực hiện phép biến đổi ta dùng một
biến đếm để đếm số lần biến đổi.
Do N có 4 chữ số nên ta chỉ cần sử dụng sắp xếp bằng thuật toán tráo đổi.
Đoạn mã chương trình đầy đủ:
program bt5;
const
tfi='dev.inp';
tfo='dev.out';
Var n, n1, n2, dem:longint;
Function gtmax(x: longint): longint;
Var s: string;
i,j: integer;
c: char;y: longint;
Begin
str(x,s);

For i:=1 to length(s)-1 do
For j:=i+1 to length(s) do
if s[i]Begin
c:=s[i];
s[i]:=s[j];
s[j]:=c;
End;
15


val(s,y);
exit(y);
End;
Function gtmin(x: longint): longint;
Var s: string;
i,j: integer;
c: char;
y: longint;
Begin
str(x,s);
For i:=1 to length(s)-1 do
For j:=i+1 to length(s) do
if s[i]>s[j] then
Begin
c:=s[i];
s[i]:=s[j];
s[j]:=c;
End;
val(s,y);

gtmin:=y;
End;
BEGIN
assign(input,tfi);
reset(input);
assign(output,tfo);
rewrite(output);
read(n);
dem:=0;
16


Repeat
n1:=gtmax(n);
n2:=gtmin(n);
n:=n1-n2;
dem≔dem+1;
Until (n=6174) or (n=0);
writeln(dem);
close(input);

close(output);

END.
Bài tập 6. Ghép số (Bài 3.15 Sách chuyên Tin)
Cho n số nguyên dương a1, a2, . . .,an (1 < n ≤ 50), mỗi số không vượt quá 2
147 483 647. Từ các số này người ta tạo ra một số nguyên mới bằng cách ghép
tất cả các số đã cho, tức là viết liên tiếp các số đã cho với nhau. Ví dụ, với n = 4
và các số 123, 124, 56, 90 ta có thể tạo ra các số mới – 1231245690,
1241235690, 5612312490, 9012312456, 9056124123, v. v... Có thể dễ dàng thấy

rằng, với n = 4, ta có thể tạo ra 24 số mới. Trong trường hợp này, số lớn nhất có
thể tạo ra là 9056124123.
Yêu cầu: Cho n và các số a1, a2, . . .,an . Hãy xác định số lớn nhất có thể tạo
ra khi ghép các số đã cho thành một số mới.
File Input: join.inp
+Dòng thứ nhất ghi số nguyên n.
+Các dòng tiếp ghi các giá trị a1, a2, ..., an.
File Output:join.out
Một dòng duy nhất là kết quả tìm được.
Ví dụ:
join.inp
4

join.out
9056124123
17


123 56 90 124
* Phân tích:
Làm thể nào để ghép các số a1, a2, ..,an với nhau thành một số lớn nhất ?
Nếu so sánh số 90 với 56 thì 90>56 nên 90 ghép trước để tạo thành 9056>5690.
Nhưng khi ghép 90 với 123 nếu so sánh 90<123 mà 90 phải ghép trước thì mới
tạo ra số lớn là 90123 còn 90 ghép sau tạo ra số 12390<90123. Như vậy ta không
thể so sánh 2 số nguyên với nhau mà dùng so sánh 2 xâu với nhau: ‘90’>’56’ nên
ghép ‘90’ trước . ‘90’ với ‘123’ thì ‘90’>’123’ do vậy ‘90’ ghép trước. Quy tắc so
sánh 2 xâu là kí tự đầu tiên khác nhau giữa chúng kể từ trái sang có mã lớn hơn
sẽ lớn hơn.
Thuật toán: Sắp xếp dãy số nguyên a 1, a2, …an thành dãy số mà thỏa mãn
ai đứng trước ai+1 nếu xâu ai > xâu ai+1. Như vậy trước khi so sánh xâu ta phải

đổi hai số nguyên ai, ai+1 sang xâu sau đó mới so sánh. Việc đầu tiên ta viết một
hàm kiểm tra xem tại hai vị trí i, j mà xâu a[i] có nhỏ hơn xâu a[j] không hàm trả
về giá trị True nếu có, giá trị False nếu không.
Sau đó lần lượt kiểm tra cứ hai vị trí mà behon(i,j) thì phải đổi chỗ a[i] với
a[j] cho nhau. Sau khi sắp xếp xong ta in dãy a viết liền sẽ được một số ghép có
giá trị lớn nhất.
Đoạn mã chương trình đầy đủ
program bt6;
const
tfi='join.inp';
tfo='join.out';
var n: longint;
a: array[0..51] of longint;
function behon(i,j: longint): boolean;
var si, sj: string;
18


begin
str(a[i],si);
str(a[j],sj);
if siexit(false);
end;
procedure main;
var i,j, tg: longint;
begin
assign(input,tfi); reset(input);
assign(output,tfo); rewrite(output);
read(n);

for i:=1 to n do read(a[i]);
for i:=1 to n-1 do

{ sắp xếp dãy a}

for j:=i+1 to n do
if behon(i,j) then
begin
tg:=a[i];
a[i]:=a[j];
a[j]:=tg;
end;
for i:=1 to n do write(a[i]);
close(input);
close(output);
end;
BEGIN
main;
END.
19


Bài tập 7.
Các phương pháp mã hóa luôn có sức cuốn hút đặc biệt đối với Rôn. Xuất
phát từ việc mọi thông tin đều được lưu trữ dưới dạng số, Rôn nghĩ rằng chỉ cần
phát triển các phương pháp mã hóa số nguyên. Mới đây Rôn đề xuất một phương
pháp mã hóa của riêng mình: mỗi số nguyên x được Rôn mã hóa thành số
nguyên y bằng cách cộng vào x các chữ số của nó (ở hệ thập phân). Như vậy, nếu
x = 12, ta sẽ có y = 12 + 1 + 2 = 15. Mã hóa bao giờ cũng đi đôi với việc giải mã.
Biết y = 15, ta phải tìm được số ban đầu x = 12.

Yêu cầu: Cho số nguyên dương y. Hãy xác định số ban đầu chưa được mã
hóa. Dữ liệu đảm bảo có kết quả giải mã.
Input: Dữ liệu nhập vào từ file encode.inp là một dòng duy nhất chứa số
nguyên y (1≤y≤109),
Output:Ghi ra file encode.out: Kết quả tìm được.
Ví dụ:
Encode.inp

Encode.out

15

12

Thuật toán : Để tìm được số ban đầu chưa được mã hóa ta phải duyệt lần
lượt các số nguyên i có giá trị từ 1 đến n nếu số nguyên i thỏa mãn i+ tổng các
chữ số của i bằng n thì i là số cần tìm và kết thúc quá trình tìm kiếm.
Do vậy ta dùng một hàm tong (x) để tính tổng các chữ số của x và x. Sau
đó kiểm tra nếu tong(x)=n thì đáp số chính là x.
Đoạn mã chương trình đầy đủ:
program

bt7;

const
tfi='encode.inp';
20


tfo='necode.out';

var n: longint;
function tong(x: longint): longint;
var s: string;
i:longint;
begin
str(x,s);
for i:=1 to length(s) do x≔x+ord(s[i])-48);
exit(x);
end;
procedure main;
var ds, i: longint;
begin
assign(input,tfi);
reset(input);
assign(output,tfo);
rewrite(output);
read(n);
ds:=0;
for i:=1 to n do
if tong(i)=n then
begin
ds:=i;
break;{Thoát khỏi vòng lặp }
end;
21


writeln(ds);
close(input);
close(output);

end;
BEGIN
main;
END.
Bài tập 8. Nhập vào số nguyên dương n (0biểu diễn của nó ở hệ đếm nhị phân. Ví dụ n=16 thì dạng biểu diễn là 10000.
Dữ liệu đọc vào từ file binary.inp có duy nhất một số nguyên dương n.
Kết quả ghi ra file binary.out là dạng biểu diễn của n trong hệ nhị phân.
Ví dụ:
Binary.inp

Binary

16

10000

Thuật toán: Bài tập này các em dễ dàng làm được vì chỉ cần chia n chi 2
lấy phần dư lưu lại còn phần nguyên lại tiếp tục chia cho 2. Quá trình cứ như vậy
cho đến khi n=0 thì dừng lại. Nhưng vấn đề ở đây khi lưu lại phần dư ta có thể
sử dụng mảng để lưu cũng được sau đó in ra theo thứ tự ngược. Nhưng ta có thể
tiết kiệm bộ nhớ bằng cách dùng xâu s để lưu dạng biểu diễn nhị phân của n.
Lệnh str(k,x) để đổi số dư k sang xâu kí tự.
Program bt8;
Const tfi=’binary.inp’;
Tfo=’binary.out’;
var n,k:longint;
s,x:string;
22



begin
assign(input,tfi);
reset(input);
assign(output,tfo);
rewrite(output);
readln(n);
s:='';
while (n>0) do
begin
k:=n mod 2;
n:=n div 2;
str(k,x);
s:=x+s;
end;
write(s);
close(input);
close(output);
end.
Bài tập 9. Tính và đưa ra màn hình tổng các chữ số của một số nguyên
viết trong cơ số b. Với n và b được nhập từ bàn phím. Ví dụ n=446, b=16 thì
dạng biểu diễn là 1BE. Tổng của nó là 1+10+15=26. (giải thích 10 quy ước là ‘A’
, 11 là ‘B’, 12 là ‘C’,…
Input: Dữ liệu đọc vào từ file sums.inp gồm có một dòng chứa hai số
nguyên dương n, b hai giá trị cách nhau một dấu cách.

23


Output: Kết quả ghi ra file sums.out là một số nguyên duy nhất là kết quả

tìm được.
Ví dụ:
sums.inp

sums.out

446 16

26

Thuật toán: Trước hết ta khai báo một hằng xâu mẫu là các chữ số của hệ
cơ số b bất kì. Để tìm dạng biểu diễn trong cơ số b ta lấy n chia liên tiếp cho b
lấy phần dư để lại phần nguyên cho đến khi n=0 thì dừng lại. Sau đó viết ngược
lại từ dưới lên. Ta thấy khi r=3 thì số 3 ở trong mẫu lại ở vị trí 4 do vậy phải là
mau[r+1].
Sau khi có được biểu diễn trong cơ số b là xâu s. Để tính tổng các hệ số ta
duyệt từng kí tự trong xâu chính là các hệ số biểu diễn của số đó. Kí tự thứ i có
giá trị là mã của kí tự đó trừ đi 48 đối với số và trừ đi 65+10 đối với dạng chữ cái
A, B,…Z.
Đoạn mã chương trình đầy đủ:
program bt9;
const mau=’0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ’;
tfi='sums.inp';
tfo='sums.out';
Var

s:string;
n,b:longint;

function doiso(n:longint;b:byte):string;

var kq:string; r:longint;
begin
kq:=’’;
while n>0 do
24


begin
r:=n mod b;
kq:=mau[r+1]+kq;
n := n div b;
end;
exit(kq);
begin
assign(input,tfi);
reset(input);
assign(output,tfo);
rewrite(output);
readln(n,b);
s≔doiso(n,b));
for i:=1 to length(s) do
if (s[i]>=’0’ )and (s[i]<=’9’) then
t:=t+ord(s[i])-48
else

if (s[i]>=’A’ and (s[i]<=’Z’) then
t:=t+ord(s[i]-65+10);

writeln(t);
close (input);

close(output);
end.
Bài tập 10 (Đề thi HSGT năm 2013)
Người ta lập số nguyên a bằng cách ghép n số nguyên tố đầu tiên với nhau
(theo thứ tự). Ví dụ:
• n=1 ta được số a=2
25


×