Phép đệ qui gián tiếp indirect recursion xảy ra khi một hàm a gọi một hàm b , sau đó hàm b lại gọi hàm a .Pascal cho phép các hàm đệ qui và trong một số trường hợp nó tỏ ra là rất có íc
Trang 1PHÉP ĐỆ QUI
Thuật ngữ ĐỆ QUI (recursion ) chỉ tình huống một hàm tự gọi chính nó một cách trực tiếp hoặc gián tiếp Phép đệ qui gián tiếp (indirect recursion ) xảy ra khi một hàm a() gọi một hàm b() , sau đó hàm b() lại gọi hàm a() Pascal cho phép các hàm đệ qui và trong một số trường hợp nó tỏ ra là rất có ích
Ví dụ phép đệ quy để tính giai thừa
(n dấu căn ) với x là giá trị được cho từ bàn phím
//chuong trinh de qui de tinh can so
program bt;
var n,number:longint;
x,result:real;
{dinh nghia de qui giai thua}
function f(n:longint) :real;
Trang 2ví dụ giá trị nhập vào là x==3 tức là ta cần tính factoria(3) ,hàm này sẽ được tính như sau :
dãy này xuất hiện tự nhiên và đặc biệt là hình thành dạng xoắn ốc Tỷ số của các số
Fibonacci liên tiếp hội tụ về một hằng số 1.618 số này lại xuất hiện nhiều lần trong tự nhiên và được gọi là tỷ số vàng (golden ratio hay goden mean )
Trang 3for i:=1 to dem-1 do
for j:=i+1 to dem do
for i:=dem+1 to dem2-1 do
for j:=i+1 to dem2 do
Trang 4end;
for i:=dem+1 to dem2 do write(b[i]:4);
writeln('Xuat day chua sap xep : ');
for i:=1 to n do write(a[i]:3);
for i:=1 to n do a[i]:=b[i];
writeln('Xuat day sau khi sap xep : ');
for i:=1 to n do write(a[i]:4);
type taptrung=set of byte;
var a:array[1 10] of byte;
Trang 7Write('Nhap chuoi ky tu 1 : ' );readln(s1);
Write('Nhap chuoi ky tu 2 : ' );readln(s2);
j:=1;
For i:=1 to length(s1) do
Begin
t:=false;
Trang 8While (j<=length(s2))and not(t) do
Trang 9dem:=1;
For i:=1 to length(st) do
If st[i]=' ' then dem:=dem+1;
Writeln('Chuoi co ',dem,' chu ')
Trang 10Bài 11 viết chương trình nhập vào một dãy n số nguyên và in ra màn hình các thông tin sau : (
nếu không có số nào thỏa mãn thì đưa ra thông báo không có )
-Số hạng âm lớn nhất của dãy và chỉ số của nó
-Số hạng dương nhỏ nhất của dãy và chỉ số của nó
-Số lượng số hạng dương liên tiếp nhiều nhất
-Số lượng số hạng âm liên tiếp có tổng lớn nhất
-Số lượng các số hạng liên tiếp đan dấu nhiều nhất
Trang 11if(i=n) then write('Khong co phan tu am :')
Trang 12if b[i]>min then min:=b[i];
writeln('So phan tu duong lien tiep nhieu nhat la :',min); i:=1;k:=0;
if max <= tong[i] then max:=tong[i];
writeln('So phan tu am lien tiep co tong lon nhat
if max<tong[i] then max:=tong[i];
write('Dan dau :',max);
for i:=1 to n do
write(a[i]:4);
readln;
end
Trang 13Bt12)Nhập từ bàn phím một số tự nhiên N Lập chương trình tìm tất cả các số hòan hảo có gia trị từ 1 đến N (nếu có )
( số hòan hảo là một số tự nhiên thỏa mãn điều kiện : Giá trị số đó bằng các ước thực sự ( không kể số đó )
Nhập từ bàn phím một số tự nhiên N Lập chương trình tìm tất cả các số hòan hảo có giá trị từ
1 đến n (nếu có )
( số hòan hảo là một số tự nhiên thỏa mãn điều kiện : giá trị số đó bằng tổng các ước thực sự (không kể số đó ) của nó)
program bt;
Trang 15Bt14 : tồng các lập phương
Có bao nhiêu phương pháp viết số tư nhiên N cho trước thành tổng lập phương của 2 số tự nhiên :
N=i 3 +j 3
Sự hóan vị của các số hạng không được tính, không được sử dụng phép nâng lũy thừa lên 1/3.mở rộng bài tóan nhập vào n xuất ra tất cả các số có thể viết dưới dạng tổng của 2 số lập phương
Trang 16for i:=1 to n do b[i]:=0;
for i:=1 to n do b[a[i]]:=b[a[i]]+1;
Trang 17Cho trước mảng số A[1:m,1:n]
BT18 :Bài tóan xếp hậu : lịet kê tất cả các cách xếp n quân Hậu trên bàn cờ nxn sao cho chúng không ăn được lẫn nhau
for i:=1 to n do a[i]:=true;
for i:=2 to 2*n do b[i]:=true;
for i:=1-n to n-1 do c[i]:=true;
Trang 18write('Nhan mot phim de xem tiep ');readln; end;
if a[j] and b[i+j] and c[i-j] then
begin {chap nhan j}
x[i]:=j;
{ghi nhan trang thai moi }
a[j]:=false;b[i+j]:=false;c[i-j]:=false;
if i=n then result else try(i+1);
{tra lai trang thai cu }
BT19 : cho môt file văn bản dạng text VAN_BAN.TXT trong đó có chứa một đọan văn bản
Câu a : đọc tệp văn bản đó và in ra màn hình
Câu b : Sửa đọan văn trên theo qui tắc sau :
+ Bỏ đi các dấu cách không cần thiết (nếu có 2 dấu cách liên tiếp thì giữ lại 1 )
+Trước một trong 4 dấu : , ; : không được có dấu cách
+Sau một trong 4 dấu : , ; : phải có dấu cách
+đầu một câu phải viết hoa
Trang 19for i:=1 to length(st) do
if ((st[i]='.') or (st[i]=',') or (st[i]=':' ) or (st[i]=';')) and (st[i-1]=#32) then
delete(st,i-1,1);
for i:=1 to length(st) do
if ((st[i]='.') or (st[i]=',') or (st[i]=':' ) or (st[i]=';')) and (st[i+1]<>#32) then
Trang 20Bt20 :Đệ qui quay lui và phương pháp nhánh cận
Bài tóan tháp hà nội là một bài tóan cơ bản của thuật tóan đệ qui Bài tóan phát biểu đơn giảnnhư sau : Cho 3 cọc A,B,C Coc A chứa N đĩa với quy tắc trên nhỏ dưới to , mỗi lần chuyển chỉ được chuyển một đĩa từ cọc này sang một trong 2 cọc còn lại và giữ nguyên trật tự to nhỏ ,Hãy đưa ra một cách chuyển N đĩa từ A-> C
Trang 21write(F,'so lan chuyen :',dem);
write('So lan chuyen :',dem);
Trang 22writeln(F,'So lan chuyen : ',dem);
write('so lan chuyen : ',dem);
Cần sắp xếp lại các số nằm trong xâu ký tự trên Kết quả được ghi trong tệp có tên
OUTPUT.B2 vị trí các ký tự khác số được giữ nguyên
Trong ví dụ trên kết quả là xâu sau đây
Trang 24Thiết kế xây dựng thư viện của người sử dụng chứa các hàm thủ tục tự tao
Xây dựng Unit tự tạo
Giả sử bạn đã có tệp turbo.exe ,turbo.tpl ,tpc.exe chứa trong thư mục Tp
Sọan thảo một chương trình pascal có tên tệp là Myunit.pas chứa trong thư mục Tp ( như vậy bạn có 4 tệp tất ca û )
if y=0 then U:=x
else U:=U(y,x mod y);
Trang 27tục bạn vừa tạo thành đó là procedure bac2(Nhà kinh doanh,b,c :integer); Một cách khác để
tạo Myunit.tpu từ Myunit.pas mà không phải tháot ra khỏi turbopascal là chọn Menu
Compile , chọn lệ h Destination đổi memory thành Disk Sau đó nhấn phím Alt+F9 để dịch myunit pas
(dịch mà không chạy , không ấn phím Ctr+f9) Khi đó trên đĩa của bạn xuất hiện
Myunit.tpu đây là thư viện chương trình con của bạn đã được mã hóa
Cách sử dụng các unit
Bây giờ bất cứ chương trình nào muốn sử dụng chương trình con Procedure Bac2( ) trong Myunit.tpu thì chỉ cần gọi thư viện Myunit.tpu bằng dòng lệnh
Uses myunit;
Như vẫn thường dùng khi gọi các thư viện chuẩn của Pascal : Uses crt;uses Graph
Mỗi khi goi các chương trình con nào đó ta chỉ việc truyền các đối số cụ thể vào các đối hình thức của chúng ,tùy tình huống và yêu cầu của chương trình gọi
Ví dụ : viết chương trình giải phương trình bậc 2
uses myunit;
var a,b,c:integer;
begin
write('Nhap a,b,c ');readln(a,b,c);
if a=0 then write('Nhap lai du lieu ')
Bt22 sắp xếp dãy số
Cho dãy số nguyên a1,a2,…an (n<=1000)
Hãy tìm cách thực hiện một số ít nhất phép đổi chổ hai số hạng bất kỳ của dãy để thu được một dãy số mà số lẻ đứng ở vị trí lẻ , số chẵn đứng ở vị trí chẵn
Dữ liệu : vào từ file văn bản DAYSO.INP
.Dòng đầu tiên chứa số nguyên dương n ;
dòng thứ I trong n dòng tiếp theo chứa số hạng ai của dãy đã cho (-32767<=ai <=32767 )I=1,2…n)
Kết quả ghi ra file văn bản DAYSO.OUT
Dòng đầu tiến ghi số lượng phép biến đổi cần thực hiện k ( qui ước k=-1 , nếu không thể biến đổi được dãy số đã cho thành dãy đã cho ttheo yêu cầu của đề bài );
Nếu k>0 thì dòng thứ j trong k dòng tiếp theo ghi chỉ số của 2 số hạng cần đổi chổ cho nhau ởlần đổi thứ j (j=1,2, k);
Ví dụ
Trang 28DAYSO.INP DAYSO.OUT DAYSO.INP DAYSO.OUT6
Trang 29begin
Trang 30end;
tim cac so thoa man dieu kien dau bai ghi vao mang s.Ham cho
(* -so luong cac (* -so tim duoc
-*)function tim:integer;
writeln('uscln cua ',a,' va ',b,'la : ',uscln(a,b));
writeln('so dao cua ',a,' la : ',sodao(a));
if ntcn(a) then write(a,'nguyen to cung nhau voi so dao cua
no ',sodao(a))
Trang 31else write(a,'khong nguyen to cung nhau voi so dao cua no ',sodao(a));
từ (4) ta có (a+c) la số chẵn Do c lẻ ,(a+c) chẵn nên a lẻ
nếu biết được a,c ta tính được x=100*a+10*( (a+c) div 2)+c=105*a+6*c
Trang 34for i:=1 to n do t:=t+a[i];
if odd(t) then exit;
write('tiep tuc ');readln(ok)
until upcase(ok)='K';
end;
begin
test;
Trang 35Bài 1.6 (Chia mảng tỷ lệ 1:k) Tìm cách chia mảng nguyên dương a[1 n] cho trước thành hai đoạn có tổng các phần tử trong đoạn này gấp k lần các phần tử trong đoạn kia , k nguyên dương
for i:=1 to n do t:=t+a[i];
if t mod (k+1)<>0 then exit;
Trang 36writeln('Doan thu nhat tu a[',1,' ',i,']');
writeln('Doan thu hai tu a[',i+1,' ',n,']');
Chương 2 DỮ LIỆU VÀO RA
Bài 2.1 (Sinh ngẫu nhiên theo khoảng ) sinh ngẫu nhiên cho mảng nguyên a n phần tử nằm trong khoảng –M M ;M>0
{b2.1Sinh ngau nhien cho mang a n phan tu nam trong khoang
Trang 37for i:=2 to n do a[i]:=a[i-1]+random(n);
Trang 38Bt 2.4 (sinh ngau nhiên ) sinh ngẫu nhiên cho mảng nguyên a n phần tử tạo thành k đoạn liên tiếp có tổng các phần tử trong mỗi đoạn là bằng nhau
Bài 2.4 đặc tả :
(1) chọn số lượng các phần tử trong mỗi đoạn là random(n div k)+1 , khi đó tổng số các phần tử phát sinh ngẫu nhiên sẽ không vượt quá k*(n div k) <=n
(2) sinh t:=raNdom(n)+1 là tổng định trước cho mỗi đoạn
(3) Giả sử a[i i+m] là đoạn thứ j cần được sinh ngẫu nhiên sao cho a[I]+a[I+1]+…+a[I+m]
=t Ta sinh đoạn này nhuu sau :
cộng từng vế của các bất đẳng thức trên ta có
bài 2.8b Lập trình để máy tính chơi nhạc bài “làng tôi “ của nhạc sĩ văn cao ( làng tôi xanh bóng tre , từng tiếng chuông ban chiều )
Trang 39writeln('Moi ban choi nhac ');
writeln('d:do| r:re| m:mi|f:fa|s:sol| ');
writeln('l:la| x:xi| g:do|h:re|n:mi ');
writeln;writeln;writeln;
repeat kytu:=readkey;
case kytu of
Trang 41bai2.9 sinh cac so khong qua 3 chu so co do cao h va ghi vao tep fn
(* -*)
if h>=9 then maxa:=9 else maxa:=h;
if h>=18 then mina:=h-18 else mina:=0;
for a:=mina to maxa do
Trang 422 3 –1 4 5 3 7 1
bài 212 (đọc tệp vào một mảng biết 1 kích thước ) Đọc dữ liệu kiểu nguyên từ một tệp văn bản có tên fn vào một mảng 2 chiều Tệp có câu trúc như sau : số đầu tiên chỉ số lượng cột của mảng tức là số phần tử trên một dòng , tiếp đến là các dữ liệu ghi liên tiếp nhau trên từngdòng của mảng Các số cách nhau bởi dấu cách , thí dụ
3 –1 4 5 3 7 1
bài 2.13 (đọc mảng đối xứng ) Đọc dữ liệu kiểu nguyên từ một tệp văn bản có tên fn vào mộtmảng 2 chiều đối xứng Tệp có cấu trúc như sau : số đầu tiên ghi số lượng cột và đồng thời làsố dòng ) của mảng , tiếp đến là các dữ liệu ghi liên tiếp nhau theo nữa tam giac trên tính từ phần tử nằm trên đường chéo chính Các số cách nhau bởi dấu cách , Thí dụ
{$I-} reset(f); {$I+}
if IORESULT <>0 THEN exit;
Trang 43bài 2,12 mỗi lần đọc xong một dòng ta tăng con đếm dòng (n) thêm 1 Chú ý : có thể gặp dòng trống do đó ta cần sữ dụng hàm seeEof(f);
{$I-} reset(f); {$I+}
if IORESULT <>0 THEN exit;
Trang 44{$I-} reset(f); {$I+}
if IORESULT <>0 THEN exit;
Trang 45{$I-} reset(f); {$I+}
if IORESULT <>0 then exit;
if(y[1]=T) and (X[1]=B) then inc(d);
for i:=2 to length(y) do
Trang 46if (y[i]=T) and (y[i-1]=B) and (x[i]=B) then inc(d);
Bài 2.14 c Lập trình tính tích hai ma trận C
Bài 2.14 d Ta định nghĩa số hòan hảo là một số tự nhiên bằng tổng các ước của nó ước không kể chính nó Viết chương trình tìm mọi số hòan hảo không lớn hơn số tự nhiên cho trước với n nhập từ bàn phím
Trang 47assign(f,'d:\sonn.kqu');rewrite(f);
write('Vao so luong ngau nhien ');readln(n);
randomize;for i:=1 to n do b[i]:=random;writeln;
Chương III BÀN PHÍM VÀ MÀN HÌNH
BÀI 3.1 (bảng mã Ascii ) tạo một file có tên là ASCII DAT chứa mã ASCII để tiện dụng Dựa vào bảng này để vẽ 4 quân bài cơ rô ,pic ,nhép
Bài 3.3 (Hàm Getkey) Mỗi khi ta nhấn một phím , Trong vùng đệm 2 byte sẽ được nạp 1 hoặc
2 byte tùy theo kiểu phím đã nhấn Nếu là phím thường như a,b,c ,% ,$ , trong vùng đệm sẽ được nạp 1 byte chứa mã ASCII CỦA ký tự tương ứng Nếu như ta nhấn phím mở rộng như f1,…f10 , cac phím dịch chuyển con trỏ ,Insert ,Del ,Page Up ,Page Down trong vùng đệm sẽnạp 2 byte : byte thứ nhất có giá trị 0 , byte thứ 2 chứa mã riêng của phínm đã ân Mã riêng này có thể trùng với mã của ký tự thường , thí dụ khi ta nhấn phím mở rộng F10 trong vùng đệm sẽ được nạp 2 byte (0,68) : mã riêng 68 trùng với mã của ky tự D ,Hàm readkey cho ta ký tự của phím đã nhấn và không hiển thị ký tự đó trên màn hình , ta gọi là hàm nhận ngầm một ký tự Readkey trước hết kiểm tra xem vùng đệm của bàn phím xem còn byte nào chưa được đọc không Nếu còn readkey sẽ đọc byte đó , ngược lại , nếu vùng đệm trống readkey sẽ chờ ta nhấn một phím rồi sau đó đọc 1 byte từ vùng đệm
Trang 48Hãy viết hàm Getkey cho ra mã ASCII của phím thường đã nhấn và cho ra mã riêng của phím mở rộng cộng thêm 128 nhằm phân biệt phím thường và phím mở rộng
BÀI 3.3 (Hàm Getkey) Trước hết gọi hàm c:=readkey rồi kiểm tra giá trị của ký tự c Nếu c có mã 0 tức là đã nhấn phím mở rộng , ta cần đọc một byte thứ 2 và gán cho hàm giá trị của byte đó cộng thêm dấu hiệu nhận biết phím mở rộng là 128 Nếu c có mã khác 0 , ta gán cho hàm giá trị đó
1 2 3 4
5 6 7 8
9 10 11 12
Trang 4913 14 15 ô trống
a.đảo ngẫu nhiên các quân cờ để di chuyển từ trạng thái ban đầu về một tình trạng H nào đó b.Nhận phím di chuyển của người chơi rồi di chuyển quân cờ theo phím đó Khi nào người chơi đạt tới tìn trạng ban đầu thì xong một ván
trò chơi này có tên là 15 từng nổi tiếng ở thế kỷ 19 như trò chơi Rubic ở thời đại chúng ta chú ý : Hàm Getkey ở bài 3.2 cho mã một số ohim mở rộng dùng để điều khiển con trỏ màn hình như sau :
x=2;y=3;{ Goc tay bac cua ban co }
dx=2;dy=3 ;{khoang cach giua cac o }
{ cac ma dich chuyen con tro }
LEN=200;XUONG=208;PHAI=205;TRAI=203;
var a,b:array[1 DD,1 DD] of byte;{ban co }
xx,yy:byte;{ Toa do cua con tro }
Trang 51Gotoxy(ex,ey);write(d); den(xx,yy);
Trang 52Mảng b chứa tình trạng ban đầu của bàn cờ và dùng để kiểm tra xem mảng a có trùng với tìnhtrạng này không ( xem hàm logic Dung )
Hai thủ tục Daongaunhien và game15 đều cùng gọi đến thủ tục Chuyen(k) –dịch chuyển quângiáp với ô trống vào ô trống Ta qui ước chọn cac giá trị của k là :
0 : lên –chuyển quân năm sát dươi với ô trống vào ô trống
1: xuống - chuyển quân năm sát trái ô trống vào ô trống
2: phải - chuyển quân năm sát phải với ô trống vào ô trống
3:Trái - chuyển quân năm sát phải với ô trống vào ô trống
đương nhiên , nếu ô trống năm sát đường biên thì có thể có trường hợp không chuyển
bt 3.4
uses crt;
const BL=' ';DD=4;
x=2;y=3;{ Goc tay bac cua ban co }
dx=2;dy=3 ;{khoang cach giua cac o }
{ cac ma dich chuyen con tro }
LEN=200;XUONG=208;PHAI=205;TRAI=203;
Trang 53var a,b:array[1 DD,1 DD] of byte;{ban co }xx,yy:byte;{ Toa do cua con tro }
Trang 54inc(xx);a[xx,yy]:=0; viet(xx,yy);
dec(xx);a[xx,yy]:=0; viet(xx,yy);
dec(yy);a[xx,yy]:=0; viet(xx,yy);
inc(yy);a[xx,yy]:=0; viet(xx,yy);
Trang 55function dung: boolean;
until Upcase(chr(k)) in [#27,'Q']; Textattr:=7;clrscr;
Trang 56với mỗi cặp số nguyên dương b và k cho trước hãy lập trình để biến màn hình máy tính của bạn thành một bảng nhảy , sau đó thử viết lên tấm bảng đó để nhận được N số tự nhiên đầu tiên 1 2 … N với mỗi N cho trước
bài 3.5 (Bảng nhảy ) Với mỗi b ta cần lưu lại b giá trị nạp trước đó trong đọan [0 b-1] của mảng a đồng thời với vị trí hiển thị trên màn hình của các giá trị đó trong mảng tương ứng x,y Ta sử dụng số học đồng dư cho việc luu trữ này , cụ thể khi cần nạp vào phần tử thứ I trước hết ta nạp vào một biến đệm z , sau đó ta tăng phần tử a[ I mod b] lên k đơn vị và tìm đến cột x[ I mod b] , dòng y[I mod b] để cập nhật lại giá trị này , cuối cùng ta chuyển giá trị z vào a[I mod b] Nói cách khác ta sử dụng vùng đệm theo nguyên tắc vòng tròn Các chi tiết màn hình trong trường hợp chuyển dòng và cuộn màn hình và cuộn màn hình là đơn giản và được chỉ rỏ trong chương trình
uses crt;
const MN=50;D=6;{ chieu dai cua moi so }
ML=12;{ so luong tren mot dong }
LIM=D*ML;BL=' ';W=50;
var a:array[0 MN] of integer;{ vung dem }
x,y:array[0 MN] of byte ;{ toa do con tro man hinh}
(*Viet n so tren bang nhay bac k buoc b *)