Giả sử a1 không chia hết cho số nguyên nào trong tất cả các số từ 2 đến n thì n là writeln'Chuong trinh kiem tra tinh nguyen to.'; write'Nhap vao mot so n nguyen duong lon hon 1: ';
Trang 1CÁC BÀI TẬP VỀ BIẾN VÀ KIỂU DỮ LIỆU
BT_02_13
Nhập vào 3 cạnh a, b, c của tam giác ABC.
a) Tính diện tích tam giác.
b) Tính độ dài các đường cao
c) Tính độ dài các đường trung tuyến
d) Tính bán kính đường tròn ngoại tiếp.
HƯỚNG DẪN
a) Tính diện tích theo công thức Hê-rông:
) c p )(
b p )(
4
ac
abcR
R
4
abc
S
Đã có công thức thì lập trình không còn là chuyện lớn Sau đây là chương trình mẫu, trong
đó các biến có ý nghĩa : a, b, c là các cạnh; ha, hc, hb là các đường cao; ma, mb, mc là các trung tuyến tương ứng với các cạnh; S, p, R lần lượt là diện tích, nửa chu vi, bán kính đường tròn ngoại tiếp.
Trang 2writeln('Thong tin ve tam giac: ');
writeln('Dien tich S = ', S:0:5);
writeln('Ban kinh duong tron ngoai tiep R = ', R:0:5);
writeln('Do dai cac duong cao: ');
writeln(' xuong canh a: ha = ', ha:0:5);
writeln(' xuong canh b: hb = ', hb:0:5);
writeln(' xuong canh c: hc = ', hc:0:5);
writeln('Do dai cac duong trung tuyen:');
writeln(' xuong canh a: ma = ', ma:0:5);
writeln(' xuong canh b: mb = ', mb:0:5);
writeln(' xuong canh c: mc = ', mc:0:5);
2 2
e
)ycosx(sinln
Yêu cầu kết quả viết với độ rộng 8 cột, có 3 chữ số phần thập phân.
HƯỚNG DẪN
Ta sẽ dùng 3 biến x, y, z kiểu real, x,y để lưu 2 số nhập vào, z lưu kết quả biểu thức.
Phần khai báo biến như sau:
var
x,y,z : real;
Phần nhập dữ liệu: ta viết thông báo nhập dữ liệu rồi nhập x,y bằng lệnh readln:
writeln('Nhap 2 so thuc x,y ');
Trang 3Ta cần khai báo 3 biến thực R, C và S Thực hiện việc nhập R rồi tính C, S theo các công thức trên Sau đó in ra chúng.
writeln('Chuong trinh tinh chu vi va dien tich hinh tron.');
write('Nhap vao ban kinh r = ');
Lệnh thực hiện việc tính là lệnh gán: s := (a+b)*h/2;
writeln('Chuong trinh tinh dien tich hinh thang ');
write('Nhap 2 canh va duong cao ');
Trang 4HƯỚNG DẪN
Thuật toán có được theo cách giải trong môn toán:
Nếu a<>0 thì có một nghiệm là x= - b/a,
ngược lại (a=0) thì
nếu b<>0 thì vô nghiệm,
ngược lại (b<>0) thì có mọi số đều là nghiệm.
Rõ ràng là chúng ta có thể dùng lệnh if, và trong trường hợp này <câu lệnh> của if lại là một lệnh if:
writeln('Phuong trinh co nghiem duy nhat x = ',-b/a:0:5);
Toàn văn chương trình:
Δ 2
Nếu <0 thì phương trình vô nghiệm.
Nếu =0 thì phương trình có nghiệm kép
a
b x
2
2 , 1
Trang 5n 2
1
sn nên cách giải quyết đơn giản là thay n vào công thức để tính kết quả.
Tuy nhiên không phải lúc nào ta cũng có công thức tổng quát và tính theo công thức tổng quát không phải lúc nào cũng hiệu quả nhất nên ta tìm một cách giải quyết khác: Sn có thể định nghĩa một cách truy hồi như sau:
n;
SS
0
s
1 - n n
Trang 61 f 1, f
2 - n 1 - n n 2 1
Viết chương trình in ra các số Fibônaxi với từ 1 đến 20.
HƯỚNG DẪN
Ta dễ dàng tìm ra cách tính: cho i chạy từ 3 đến 20 rồi tính fi theo định nghĩa: fi=fi
-1+fi-2 Đặt biến f0, f1, f2 đại diện cho fi, fi-1, fi-2 ứng với mỗi giá trị của i, thế thì ta có thể viết đoạn chương trình tính như sau:
Rõ ràng cách tính này đơn giản hơn sử dụng công thức tổng quát rất nhiều:
n
f
2 5 1 2
5 1 5
Trang 7HƯỚNG DẪN
Trong chương 2 ta đã biết tính ab với a là số thực dương và b bất kỳ theo công thức
ln(a))
*(bexp
1 t
1 - n n 0
Như vậy cho i chạy từ 1 đến n và tính công thức trên ta sẽ tính tn Cấu trúc for dùng cài đặt rất thích hợp.
Đoạn chương trình như sau:
t := 1;
for i := 1 to n do t := t * a;
Biến t đại diện cho ti ứng với mỗi i trong lệnh for Trong câu lệnh t := t * a; biến t ở bên trái
là ti, giá trị t ở bên phải là giá trị trước đó của t, tức là ti-1 Câu lệnh viết đúng theo công thức truy hồi Xong vòng for i=n và t chính là giá trị tn = an Ta thông báo kết quả.
Toàn văn chương trình:
n.(n-!
1 1 0
Đặt gn=n!, theo công thức trên ta có:
n g g
1 g
1 - n n 0
Và như vậy tương tự VD_03_06 và VD_03_08 ta cũng có chương trình tính như sau:
Trang 812!
11!
11
e với n nguyên nhập từ bàn phím.
HƯỚNG DẪN
Ta có thể dựa trên chương trình tính giai thừa ở trên để tính một cách tường minh theo công thức trên Tuy nhiên cách ấy không ổn vì hàm giai thừa tăng rất nhanh theo n, nếu n quá lớn thì không thể tính được
Đặt
n!
1
3!
12!
11!
e
n r n
1 r r
1.
r 1, e
n 1
n n
-1 n 1
n n
-0 0
Và từ đó ta có thể viết đoạn chương trình tính dùng vòng lặp for như sau:
Trang 9HƯỚNG DẪN
Đặt td là số trâu đứng, tn là số trâu nằm, tg là số trâu già thoả mãn bài toán Thế thì td, tn,
tg là các số nguyên dương thoả mãn:
100
tg tn td
tg tn td
Từ phương trình thứ hai ta có 5td100 và 3tn100, suy ra 1 td 20 và 1 tn 33 Số trâu già: tg=(100-td-tn) phải chia hết cho 3 (vì số bó cỏ bọn trâu già ăn là số nguyên, bằng
tg div 3).
Như vậy ta cần tìm các số td trong khoảng 1 20 và tn trong khoảng 1 33 sao cho: tg =(100
- td - tn) chia hết cho 3 và 5*td + 3*tn + tg div 3 = 100.
Toàn văn chương trình:
Và n là số năm cần tìm nếu n là số tự nhiên bé nhất thoả mãn sn100.
Ta thấy rằng để tính trực tiếp n thì không dễ dàng nhưng chúng ta có thể sử dụng phương pháp lặp Nghĩa là chúng ta tăng dần n (bắt đầu từ 0) và tính sn theo công thức trên cho đến khi sn100.
Đoạn chương trình như sau:
n:= 0;
s:= 75;
repeat
Trang 10writeln('Dan so hien nay la 75 trieu Ti le tang 1.7%.');
writeln('Sau ',n,' nam thi dan so dat 100 trieu.');
Ta tìm hiểu thuật toán trước:
Giả sử số nguyên n (>1) không phải là số nguyên tố Suy ra nó phải là tích của 2 số nguyên
a và b (a, b>1) Giả sử a<b na.ba2 na 2a n (ký hiệu x chỉ phần nguyên của x, nghĩa là số nguyên lớn nhất nhỏ hơn x) Từ đó suy ra các số nguyên trong khoảng 2 n có ít nhất một số là ước của n.
Vậy nếu n (>1) không chia hết cho số nguyên nào trong tất cả các số từ 2 đến n thì n là
writeln('Chuong trinh kiem tra tinh nguyen to.');
write('Nhap vao mot so n nguyen duong lon hon 1: ');
Trang 11Như vậy UCLN(a,b)=a nếu b=0, =UCLN(b, a mod b) Thuật toán của ta sẽ thực hiện liên tiếp : c:= a mod b, a:=b, b:=c cho đến khi b=0 Lúc đó d:=a
Thuật toán có thể cài đặt bằng ngôn ngữ Pascal như sau, các biến đặt tên như trên:
writeln('Chuong trinh tinh UCLN.');
write('Nhap vao hai so tu nhien ');
Trang 12x n
n z , y , x 0
Ta đã xác định được khoảng xác định của x,y,z từ đó có thể dùng các vòng for để kiểm tra phương trình Ta viết như sau:
3 3 3
3 3 3
3 3 3
3 3
y x n z
y x n z
x n y 0
n x 0 y x n z
x n y 0
n x 0
Như vậy khoảng tìm kiếm đã hẹp hơn, ta cũng chỉ tìm x, y rồi tính z theo x,y và kiểm tra phương trình Đoạn chương trình có thể viết như sau:
for x := 0 to trunc(exp(ln(n)/3)) do begin
Trang 13) 3 / ) n exp(ln(
e n n e
n ln 3
1 3
a ln b b
Các cấu trúc if được đưa vào để tránh truyền đối số 0 cho hàm ln (nếu không có chúng thì khi n=8 chẳng hạn, hàm ln sẽ bị truyền đối số 0 (x=2,y=0,z=0)) Điều ấy gây lỗi khi chạy của chương trình (run-time error).
Nhận xét: đoạn trình 2 dài và rắc rối hơn đoạn trình 1 nhưng rõ ràng chạy nhanh hơn Điều
ấy cũng bình thường thôi vì không phải lúc nào cũng có phương pháp vừa hiệu quả vừa đơn giản Trong những bài toán nhỏ thì yếu tố hiệu quả thường bị bỏ qua (vì thời gian tính toán không đáng bao nhiêu) nhưng với những bài toán lớn ta luôn phải quan tâm đến tính hiệu quả của chương trình Chúng cần phải ổn định, sử dụng hợp lý không gian nhớ và nhất là phải chạy nhanh Vì thế chúng ta nên rèn kỹ năng tối ưu hoá, làm thế nào để những chương trình ta viết hiệu quả càng tốt.
writeln('Cac so x,y,z thoa man : ');
for x := 0 to trunc(exp(ln(n)/3)) do begin
Trang 14end;
end;
readln;
end
Trang 15CÁC BÀI TẬP VỀ CHƯƠNG TRÌNH CON
BT_04_01: Viết chương trình con tính chu vi và diện tích của hình chữ nhật.
Giải: Ta thấy rằng chương trình con tính chu vi, diện tích của hình chữ nhật nhất định phải
có tham số đầu vào là 2 cạnh, đó là 2 tham trị Nếu ta viết chương trình con là thủ tục thì kết quả phải lưu bằng một tham biến để đưa ra Đặt tên các thủ tục là chu_vi, dien_tich ta cài đặt như sau:
procedure Chu_vi(a,b : real; var c : real);
BT_04_02: Viết chương trình con:
a) Tính chu vi và diện tích hình tròn theo bán kính.
b) Tính diện tích tam giác, bán kính đường tròn nội và ngoại tiếp tam giác theo 3 cạnh c) Tính thể tích và đường chéo hình hộp chữ nhật theo 3 kích thước.
BT_04_03: Viết một hàm tính số ước số của một số nguyên.
BT_04_04: Viết một hàm tính ước chung lớn nhất của hai số nguyên.
Trang 16CÁC BÀI TẬP VỀ MẢNG 1 CHIỀU VÀ 2 CHIỀU
BÀI TẬP 1
Nhập vào một số n (5<=n<=10) và n phần tử của dãy a, 1<a i <100 (có kiểm tra dữ liệu khi nhập).
a) In ra các phần tử là số nguyên tố của dãy.
b) Tính ước chung lớn nhất của tất cả các phần tử của dãy.
c) Tính biểu thức sau:
n n
a
a a
Chương trình như sau:
Khai báo dữ liệu:
uses crt;
var n : integer;
a : array[1 10] of integer; {n<=10 nên mảng có tối đa 10 phần tử}
Thủ tục nhập dữ liệu, có kiểm tra khi nhập.
if (5<=n) and (n<=10) then break; {nếu thoã mãn thì dừng vòng lặp}
writeln('Khong hop le (5<=n<=10) Nhap lai!!!'); {ngược lại thì báo lỗi}
if (1<a[i]) and (a[i]<100) then break;
writeln('Khong hop le Nhap lai!!!');
Trang 17writeln('CAC PHAN TU NGUYEN TO TRONG DAY:');
for i := 1 to n do {duyệt qua mọi phần tử từ 1 đến n}
if ngto(a[i]) then writeln(a[i]); {nếu ai là nguyên tố thì in ra}
u := a[1]; {u là UCLN của các phần tử từ 1 đến i}
for i := 2 to n do u := UCLN(u,a[i]); {là UCLN của các phần tử từ 1 đến i-1 và ai}writeln('UCLN cua ca day la:',u);
end;
function hammu(a : real; n : integer): real; {hàm mũ tính an}
var s : real; i : integer;
Trang 18var i,j,tg : integer;
begin
for i := 1 to n-1 do
for j := i + 1 to n do
if a[i] > a[j] then begin
tg := a[i]; a[i] := a[j]; a[j] := tg;
if a[k] > a[i] then k := i;
writeln('Phan tu nho nhat la a[',k,']=',a[k]);
if a[k] < a[i] then k := i;
writeln('Phan tu lon nhat la a[',k,']=',a[k]);
end;
Chú ý:
1 Nếu áp dụng với mảng 2 chiều thì cũng tương tự, chỉ khác là để duyệt qua mọi phần tử
của mảng 2 chiều thì ta phải dùng 2 vòng for Và vị trí một phần tử cũng gồm cả dòng và
cột.
Ví dụ 1 Tìm phần tử nhỏ nhất và lớn nhất của mảng 2 chiều và đổi chỗ chúng cho nhau:
procedure exchange;
Trang 19var i,j,i1,j1,i2,j2,tg : integer;
if a[i1,j1] > a[i,j] then begin {so sánh tìm min}
i1 := i; j1 := j; {ghi nhận vị trí min mới}
end;
if a[i2,j2] < a[i,j] then begin {so sánh tìm max}
i2 := i; j2 := j; {ghi nhận vị trí max mới}
Ví dụ 2 Tìm phần tử lớn nhất của dòng k và đổi chỗ nó về phần tử đầu dòng.
procedure timmax(k : integer);
var i, vt, tg : integer;
begin
vt := 1; {vt là vị trí của phần tử min dòng k}
for i := 1 to n do
if a[k,i] > a[k,vt] then vt := i; {các phần tử dòng k có dạng a[k,i]}
tg := a[k,1]; a[k,1] := a[k,vt]; a[k,vt] := tg;
end;
Ví dụ 3 Sắp xếp giảm dần cột thứ k.
procedure sapxep(k: integer);
var i,j,tg : integer;
begin
for i := 1 to m-1 do {mỗi cột có m phần tử, vì bảng có m dòng}
for j := i+1 to m do
if a[i,k] > a[j,k] then begin {các phần tử cột k có dạng a[i,k]}
tg := a[i,k]; a[i,k] := a[j,k]; a[j,k] := tg;
Sau đó ta duyệt qua các phần tử từ đầu đến cuối, phần tử nào thoả mãn tính chất đó thì in ra.
Trang 20if tongus(i) = i then writeln(i);
Ví dụ 3 In ra các phần tử của mảng chia 3 dư 1, chia 7 dư 2:
for i := 1 to n do begin
if (a[i] mod 3=1) and (a[i] mod 7=2) then writeln(a[i]);
Ví dụ 4 In ra các số có 3 chữ số, tổng chữ số bằng 20, chia 7 dư 2.
Ta dùng hàm tổng chữ số đã có ở trên:
for i := 100 to 999 do begin {duyệt qua mọi số có 3 chữ số}
if (tongcs(i)=20) and (i mod 7=2) then writeln(i);
Chú ý: Nếu áp dụng với mảng 2 chiều thì cũng tương tự, chỉ khác là để duyệt qua mọi
phần tử của mảng 2 chiều thì ta phải dùng 2 vòng for.
Ví dụ, để in các phần tử nguyên tố của 1 mảng 2 chiều:
whereX: hàm cho giá trị là vị trí cột của con trỏ màn hình.
whereY: hàm cho giá trị là vị trí dòng của con trỏ màn hình.
Khi nhập 1 phần tử ta dùng lệnh readln nên con trỏ màn hình sẽ xuống dòng, do đó cần quay lại dòng của bằng lệnh GotoXY(j * 10, whereY -1 ), nếu ta muốn mỗi phần tử của ma trận ứng với 10 cột màn hình.
Trang 21write('A[',i,',',j,']='); readln(a[i,j]); {nhập xong thì xuống dòng}
gotoXY(j*10,whereY-1); {di chuyển về dòng trước, vị trí tiếp theo}end;
writeln; {nhập xong 1 hàng thì xuống dòng}
for i := 1 to m do begin {viết các phần tử của hàng i }
for j := 1 to n do write(a[i,j]:6); {mỗi phần tử chiếm 6 ô để căn phải cho thẳng cột
THUẬT TOÁN KIỂM TRA SỐ NGUYÊN TỐ
Thuật toán của ta dựa trên ý tưởng: nếu n >1 không chia hết cho số nguyên nào trong tất
cả các số từ 2 đến n thì n là số nguyên tố Do đó ta sẽ kiểm tra tất cả các số nguyên từ 2
đến có round(sqrt(n)), nếu n không chia hết cho số nào trong đó thì n là số nguyên tố.
Nếu thấy biểu thức round(sqrt(n)) khó viết thì ta có thể kiểm tra từ 2 đến n div 2.
Hàm kiểm tra nguyên tố nhận vào một số nguyên n và trả lại kết quả là true (đúng) nếu n là nguyên tố và trả lại false nếu n không là số nguyên tố.
for i:=2 to trunc(sqrt(n)) do
if n mod i=0 then exit; {nếu n chia hết cho i thì n không là nguyên tố => thoát luôn}
ngto:=true;
end;
Chú ý: Dựa trên hàm kiểm tra nguyên tố, ta có thể tìm các số nguyên tố từ 1 đến n bằng
cách cho i chạy từ 1 đến n và gọi hàm kiểm tra nguyên tố với từng giá trị i.
THUẬT TOÁN TÍNH TỔNG CÁC CHỮ SỐ CỦA MỘT SỐ NGUYÊN
Ý tưởng là ta chia số đó cho 10 lấy dư (mod) thì được chữ số hàng đơn vị, và lấy số đó div
10 thì sẽ được phần còn lại Do đó sẽ chia liên tục cho đến khi không chia được nữa (số đó bằng 0), mỗi lần chia thì được một chữ số và ta cộng dồn chữ số đó vào tổng.
Hàm tính tổng chữ số nhận vào 1 số nguyên n và trả lại kết quả là tổng các chữ số của nó:
function tongcs(n:integer): integer;
var s : integer;
begin
s := 0;
Trang 22Chú ý: Tính tích các chữ số cũng tương tự, chỉ cần chú ý ban đầu gán s là 1 và thực hiện
phép nhân s với n mod 10.
THUẬT TOÁN EUCLIDE TÍNH UCLN
Ý tưởng của thuật toán Euclide là UCLN của 2 số a,b cũng là UCLN của 2 số b và a mod
b, vậy ta sẽ đổi a là b, b là a mod b cho đến khi b bằng 0 Khi đó UCLN là a.
Hàm UCLN nhận vào 2 số nguyên a,b và trả lại kết quả là UCLN của 2 số đó.
function UCLN(a,b: integer): integer;
Chú ý: Dựa trên thuật toán tính UCLN ta có thể kiểm tra được 2 số nguyên tố cùng nhau
hay không Ngoài ra cũng có thể dùng để tối giản phân số bằng cách chia cả tử và mẫu cho UCLN
THUẬT TOÁN TÍNH TỔNG CÁC ƯỚC SỐ CỦA MỘT SỐ NGUYÊN
Để tính tổng các ước số của số n, ta cho i chạy từ 1 đến n div 2, nếu n chia hết cho số nào
thì ta cộng số đó vào tổng (Chú ý cách tính này chưa xét n cũng là ước số của n).
function tongus(n : integer): integer;
var i,s : integer;
Chú ý: Dựa trên thuật toán tính tổng ước số, ta có thể kiểm tra được 1 số nguyên có là số
hoàn thiện không: số nguyên gọi là số hoàn thiện nếu nó bằng tổng các ước số của nó.
CÁC THUẬT TOÁN VỀ VÒNG LẶP
THUẬT TOÁN TÍNH GIAI THỪA MỘT SỐ NGUYÊN
Giai thừa n! là tích các số từ 1 đến n Vậy hàm giai thừa viết như sau:
function giaithua(n : integer) : longint;
var i : integer; s : longint;
begin
Trang 23Trong Pascal ta có thể tính ab bằng công thức exp(b*ln(a)) Tuy nhiên nếu a không phải là
số dương thì không thể áp dụng được.
Ta có thể tính hàm mũ an bằng công thức lặp như sau:
function hammu(a : real; n : integer): real;
var s : real; i : integer;
!
x
!
x x e
n x
3 2
Đặt:
n!
x
!
x
!
x x
s n n
32
i
i
i-r s
s
i x r
r
, r s
1 1 0
Khi đó, ta có thể tính công thức chuỗi trên như sau:
function expn(x: real; n : integer): real;
var s,r : real; i : integer;