21

Click here to load reader

bai tap BFS

Embed Size (px)

Citation preview

Page 1: bai tap BFS

[Thuật toán] Loang trên ma trận--------------------------------------------------

THUẬT TOÁN LOANG TRÊN MA TRẬN (DÃY 2 CHIỀU)

------Tư tưởng của thuật toán loang thật ra cũng rất đơn giản. Hãy tưởng tượng có một nàng công chúa bị bắt giam vào 1 mê cung, nàng bí quá, lôi ĐTDĐ ra fone cho hoàng tử.

Hoàng tử tức tốc dẫn theo một đạo quân (giả sử rằng số quân của chàng ta là ko giới hạn). Khi đến cổng vào mê cung, chàng may mắn gặp một "bậc thánh nhân", người cho

chàng biết rằng công chúa đang bị giam trong phòng [X,Y] nào đó. À, bây giờ trong đầu chàng nghĩ đến 2 hướng sau:

_ Chàng quyết định solo đi vào mê cung, dĩ nhiên trên tay cầm 1 cuộn chỉ. Khi vào cổng, chàng bắt gặp T căn phòng, chàng sẽ đi vào từng phòng một, bước vào T1, chàng lại gặp

T2 cửa, ... , cứ thế đến khi ko có đường đi, chàng sẽ lần ngược theo đường chỉ, đánh dấu vào cánh cửa chàng đã đi rồi, và chọn 1 cửa khác. Với cách này, chàng sẽ tìm được phòng

có công chúa, dĩ nhiên, nếu chàng ko gục ở giữa đường.

_ Tận dụng nguồn binh lực hùng hậu của mình, chàng ra hiệu lệnh "Toàn lực lục soát". Đi vào mê cung, bắt gặp T căn phòng, chàng chia đoàn binh thành T đạo, cứ thế. Dĩ nhiên,

mỗi binh sĩ đều đc trang bị phương tiện liên lạc để khi tìm thấy công chúa sẽ phát hiệu lệnh "Rút lui". Vậy, với cách này ta sẽ tìm được công chúa với quãng đường đi từ cửa mê

cung đến phòng giam là ngắn nhất. Nhưng, nảy sinh một bất cập là, nếu binh sĩ tìm được công chúa rồi, thì làm sao lần ra lại cửa mê cung đây??? Đương nhiên hoàng tử ko thể

chấp nhận chuyện để người yêu mình chung phòng với một đám binh sĩ ~~. Chàng ra lệnh rằng, trước khi vào mỗi cửa, phải dùng kiếm vạch mũi tên xuống đất, mũi tên này sẽ

hướng đến cửa các binh sĩ đã đi vào trước khi gặp căn phòng. Ví dụ khi vào cổng mê cung, 1 tốp binh sĩ đi vào cửa T1, gặp N2 cửa khác, chia binh lực ra, với mỗi cửa T2, các binh

sĩ sẽ vạch mũi tên hướng về cửa T1, tức cửa đã dẫn họ tới N2 căn phòng. Nhờ đó họ sẽ lần được đường thoát khỏi mê cung.

Từ đây, ta sẽ hình thành 2 phương pháp tìm đường đi, trong bài viết này, chúng ta sẽ tìm hiểu cách thứ hai, mà theo cách gọi thông thường là LOANG: Từ một vị trí có tọa độ

A(x,y) cho sẵn, bạn buộc phải tìm đến một vị trí B(x’,y’) sao cho quảng đường đi là ít nhất có thể và in ra đường đi từ A đến B đó.

------Có khá nhiều phương pháp tìm đường đi, trong đó có BFS (Breadth First Search - Tìm kiếm theo chiều rộng, còn gọi là loang), DFS (Depth First Search - Tìm kiếm theo

chiều sâu). Như đã nói, chúng ta chỉ xem xét vềBFS trong bài viết này. Có nhiều cách cài đặt BFS như là hàng đợi (queue) hoặc dùng 2 mảng tính qua lại lẫn nhau (mảng chứa

những phòng có thể đi tiếp, và mảng chứa những phòng bắt gặp khi đi vào những phòng ở trên). Tuy nhiên các mà tôi sắp giới thiệu cho bạn đây là một cách không chính thống,

phương pháp này loang theo chiều rộng và cách thức tốn khá nhiều tài nguyên. Song, với thuật toán Loang này, bạn sẽ dễ dàng làm những bài toán Loang đơn giản hay phức tạp

với dữ liệu yêu cầu nhỏ. Thuật toán được trình bày ngắn gọn như sau:

------Cứ một nơi bạn đặt chân tới và thấy là nơi cho phép thì đánh dấu nơi đó với 1 số [i]k tăng dần (để xác định rằng bạn đã đi đến đó và ô đó là nơi bạn đi đến lần thứ k). Cứ tiếp

tục như thế cho đến khi gặp điểm dừng thì thoát khỏi chương trình.

var  a        :  array[1..100,1..100] of byte; khai báo mảng kiểu dữ liệu số nguyên đếm được

          Near    :  array[1..2] of record khai báo mảng kiểu bản ghi

                                                  x,y : byte;

                                          end;

    Procedure Loang;

    Var i,j,z : byte;

    Begin

            Repeat  {Kiểm tra nếu phần tử cuối cùng a[n,m] khác 0 (gặp điểm dừng) thì sẽ kết thúc, ngược lại thì làm những công việc sau }

                  Flag := false; {Hiện tại, chưa tìm đc chỗ để loang}

                  For i := 1 to n do

                    For j := 1 to m do {Duyệt tất cả phần tử mảng}

                    Begin

                              If (a[i,j] = e) then  {Nếu phát hiện có dấu chân đc đánh dấu tại bước loang thứ e thì bắt đầu loang tiếp}

                              Begin

                                          {Tạo những phần tử xung quanh i,j. Ở đây tôi làm dưới và phải}

                                          Near[1].x := i+1;          Near[1].y := j;

Page 2: bai tap BFS

                                          Near[2].x := i;            Near[2].y := j+1;

    

                                          For z := 1 to 2 do {Bắt đầu duyệt các phần tử xung quanh đó}

                                          Begin

                                                  If (a[Near[z].x,Near[z].y] = 0) then {Nếu kô gặp chướng ngại vật}  (Near là mảng hằng giống như

trong bài toán mã đi tuần}

                                                  Begin

                                                          Flag := true; {Đã tìm được chỗ loang}

                                                          a[Near[z].x,Near[z].y] := e+1; {Đánh dấu chân đã loang tới đếm được ở bước thứ e + 1}

                                                  End;        

                                          End;

                              End;

                    End;

                  If  Flag then e := e+1;

            Until a[n,m] <> 0;

    End;

        BEGIN

            ReadInput;

            e := 1;

            Loang;

            Print;

            Readln;

    END.

Thực tế cho thấy, kết quả của bài toán sẽ in ra 1 ma trận đã được loang "tá lả". Bởi vì bạn không kiểm soát và cho biết một đường loang nhất định, do đó từ 1 bước sẽ có nhiều

hướng đi.

Okay, để giải quyết vấn đề này, công việc chỉ còn là ở bạn. Tôi đã cung cấp cho bạn cách Loang ra toàn ma trận, nhiệm vụ của bạn bây giờ là hãy dùng cách tương tự để viết một

thủ tục xóa những Loang dư thừa, không cần thiết.

Vd:Trích dẫn:

Ma trận gốc:0 0 1 0 10 0 0 1 10 0 0 0 10 0 0 0 0

Ma trận Loang:1 2 1 0 12 3 4 1 13 4 5 6 14 5 6 7 8

Page 3: bai tap BFS

Ma trận đã xóa Loang dư:1 0 1 0 12 0 0 1 13 0 0 0 14 5 6 7 8

Xong. Thuật toán cài đặt khá đơn giản và chạy khá hiệu quả, tuy nhiên thời gian khá chậm do độ phức tạp tương O(k*n^2). Bạn có thể thêm một chút cải tiến để cải thiện tốc độ.Bài 1 : Tìm dãy con tăng dài nhất :            Cho mảng A(N) . Cần xoá ít nhất một số phần tử của dãy này sao cho các phần tử còn lại tạo thành dãy tăng nghiêm ngặt . Ta  xây dựng mảng T(N) và mảng D(N) với ý nghĩa :            + T[i] là chỉ số j ( trong mảng A ) của phần tử đứng trước phần tử có chỉ số i (trong mảng A ) khi xét dãy kết quả .            + D[i] là độ dài của dãy kết quả khi bài toán trên mảng A(N) mới được xét từ phần tử 1 đến phần tử i ( Nghiã là ta tạm giải bài toán với kích thước đến i - đó là kích thước không vượt quá kích thước bài toán đã cho ) . Công thức qui hoạch động của bài toán này là : D[i] = Max { D[j] + 1 /  "  j :  j <i  mà  A[j] < A[i] } Chú ý              1- Khởi trị bài toán : T[1] = 0 , D[1] = 1            2- Xử dụng công thức trên với i>1 , mỗi lần tìm được j thoả mãn cần ghi lưu T[i]=j            3- Khi xong i=N , tìm lại kết quả nhờ duyệt mảng D . Trước hết tìm j có D[j] lớn nhất , sau đó truy hồi dần tìm j bằng cách thay j bởi T[j] cho đến khi T[j]=0            Các vị trí j tìm được chính là các vị trí trong mảng A cần giữ lại nhưng theo thứ tự ngược . Thí dụ

 Chỉ số 1 2 3 4 5 6 7 8 9 10 11 12

A 6 12 8 11 3 4 1 7 5 9 10 2

T 0 1 1 3 0 5 0 6 6 8 10 7

D 1 2 2 3 -1 -21 -33 -4 -5 2

 Dãy kết quả là :

 Chỉ số 5 6 8 10 11

A 3 4 7 9 10

 Bài 2 : Xoá ít nhất một số phần tử của 2 dãy sao cho sau khi xoá  2 dãy như nhau Gợi ý : Cần xây dựng mảng C(N,M) với ý nghĩa : C[i,j] là độ dài của dãy còn lại nếu dãy A chỉ xét tới chỉ số i và dãy B chỉ xét tới chỉ số j . Đương nhiên C[1,j] = 0 nếu A[1] không có trong dãy B(j) ,ngược lại thì  C[1,j] = 1 ; tương tự C[i,1] = 0 nếu B[1] không có trong dãy A(i) ,ngược lại thì  C[i,1] = 1 . Những trường hợp còn lại C[i,j] được tính theo công thức truy hồi sau : C[i,j] = Max{C[i,j-1],C[i-1,j],C[i-1,j-1]+x} ( Vì :     nếu A[i]=B[j] thì C[i,j]= C[i-1,j-1]+1            nếu A[i] không có trong B(j) thì  C[i,j]= C[i-1,j]            nếu B[j] không có trong A(i) thì  C[i,j]= C[i,j-1]  )A - Lời giảiBài 1 :{Cho N nguyen duong N<=10000 so , tim day tang dai nhat }Uses   Crt;Const  Max      = 10000; {Khai báo biến không đổi}            Fi         = 'BL14.inp'; {Tạo file nhập}            Fo        = 'BL1.out'; {File xuất}Type   Mang   = Array[1..Max] of Integer;Var      A,D,T  : Mang;            N,dem : LongInt;            F          : Text;Procedure TaoF;            Var      F          : Text;                        i           : LongInt;            Begin                        Assign(F,Fi);Mở tập tin có tên là Fi

Page 4: bai tap BFS

                        ReWrite(F);                        Write('Nhap N = ');                        Repeat                                    {$I-} Readln(N);{$I+}                        Until (IoResult=0) and (N>0) and (N<=Max);                        Writeln(F,N);                        For i:=1 to N do                        Begin                                    Write(F,10000-i+1:7);                                    {Write(F,Random(100):3);}                                    If i mod 10 =0 then Writeln(F);                        End;                        Close(F);            End;Procedure Nhap;            Var   i : LongInt;            Begin                        FillChar(A,Sizeof(A),0); (FillChar Ðiền một số byte có giá trị vào; Sizeof: cho kích thước của biến hay kiểu dữ liệu)                        Assign(F,Fi);                        Reset(F);                        Readln(F,N);                        For i:=1 to N do Read(F,A[i]);                        

Page 5: bai tap BFS

Close(F);            End; Procedure KhoitriT_D;            Begin                        FillChar(T,Sizeof(T),0);                        T[1] := 0;                        D[1] := 1;            End; Function Vitritruoc(i : LongInt) : LongInt;            Var      j,Ld,Lj : LongInt;            Begin                        Ld := 0;                        Lj := 0;                        Vitritruoc := 0;                        For j:=i-1 downto 1 do                                    If A[j]<=A[i] then                                                If D[j]>Ld then                                                Begin                                                            Ld := D[j];                                                            Lj := j;                                                End;                        Vitritruoc := Lj;           End; Procedure TaoT_D;            Var i : LongInt;            Begin                        KhoitriT_Dl;                        For i:=2 to N do                        Begin                                    T[i]       := Vitritruoc(i);                                    If T[i]=0 then    D[i] := 1                                                Else      D[i] := D[T[i]]+1;                        End;            End; Function MaxD : Longint;            Var      i,p,Li : LongInt;            Begin                        p := -MaxInt;                        Li := 0;                        For i:=1 to N do                                    If D[i]>p then                                    Begin                                                p          := D[i];                                                Li         := i;                                    End;                        MaxD := Li;            End; Procedure Timketqua;            Var i : LongInt;            Begin                        i           := MaxD;                        D[i]      := -D[i];                        dem    := 1;                        Repeat                                    i := T[i];                                    If i<>0 then                                    Begin                                                D[i] := -D[i];

                                                Inc(dem)                                    End;                        Until i=0;            End; Procedure Ghi;            Var      F          : Text;                        i           : LongInt;            Begin                        Assign(F,Fo);                        ReWrite(F);                        Writeln(F,dem);                        dem := 0;                        For i := 1 to N do                                    If D[i]<0 then                                                Begin                                                            Write(F,A[i]:7);                                                            Inc(dem);                                                            If dem mod 10 = 0 then Writeln(F);                                                End;                        Close(F);            End; BEGIN            Clrscr;            {TaoF;}            Nhap;            TaoT_D;            Timketqua;            Ghi;            Writeln('Da xong ');            Readln;END. Bài 2 :Uses   Crt;Const  Max      = 100;            Fi         = 'qhdong2.inp';            Fo        = 'qhdong2.out';Type   M1       = Array[1..Max] of Byte;            M2       = Array[1..Max,1..Max] of Byte;Var      A,B      : M1;            C         : M2;            F,F2     : Text;            M,N     : Byte;Procedure TaoF;       Var           i           : Byte;                        F          : Text;       Begin           Write('Nhap do dai 2 mang : M,N = ');           Readln(M,N);           Assign(F,Fi);           ReWrite(F);           Writeln(F,M,' ',N);           For i:=1 to M do Write(F,Random(100+1),' ');           Writeln(F);           For i:=1 to N do Write(F,Random(100+1),' ');           Close(f);       End;Procedure DocF;       Var           i           : Byte;

Page 6: bai tap BFS

       Begin             Assign(F,Fi);             Reset(F);             Readln(F,M,N);             For i:=1 to M do Read(F,A[i]);             Readln(F);             For i:=1 to N do Read(F,B[i]);             Close(F);       End;

Function Max3(x,y,z : Byte) : Byte;       Var           phu       : Byte;       Begin            If x>y then phu := x Else phu := y;            If z>phu then phu := z;            Max3 := Phu;       End;Function Co(x,L : Integer;D : M1) : Boolean;     Var                                   : Byte;

Bài 1cho xâu S ( độ dài không vượt quá 10) chỉ gồm các kí tự 'A' đến 'Z', các ký tự đôi 1 khác nhau. hãy liệt kê các hoán vị khác nhau của xâu SDư liệu vào: nhập từ file HVX.INP gồm 1 dòng duy nhất là xâu SDữ liệ ra: Ghi ra file HVX.OUT gồm nhiều dòng, mỗi dòng là 1 hoán vị của xâu SBài 2Cho số nguyên dương n (n<=20). hãy liệt kê tất cả các xâu độ dài n chỉ gồm 2 ký tự 'A' và 'B' sao cho ko có 2 ký tự 'B' nào đứng cạnh nhau.Dữ liệu vào: nhập từ file AB.INP gồm 1 dòng duy nhất ghi số nguyên dương nDữ liệu ra: Ghi ra file AB.OUT gồm nhiều dòng, mỗi dòng là 1 xâu độ dài n tìm đượcBài 3Cho dãy số A gồm n ( n<=10) số nguyên A1 ,A2, . . ,An và 1 số nguyên dương k ( 1<k<n) Hãy đưa ra 1 cách chia dãy số thành k nhóm sao cho các nhóm có tổng bằng nhau.Dữ liệu vào: Nhập từ file CHIA.INP gồm dòng đầu tiên chứa số nguyên n và k; dòng sau chứa dãy số nguyên ADữ liệu ra: Ghi ra file CHIA.OUT gồm k dòng, mỗi dòng là 1 nhóm.Bài 4 ( làm cũng đc. hì )1 xâu X = x1,x2,...,xm đc gọi là xâu con của xâu Y = y1,y2,...,yn. Nếu ta có thể nhận đc xâu X từ xâu Y bằng cách xóa đi 1 số kí tự, tức là tồn tại 1 dãy các chỉ số: 1<=i1<i2<...<im<= n để x1=yi, x2 = yi,..., xm = yi. Ví dụ X = 'adz' là xâu con của Y = 'baczdtz', i1 = 2 < i2 = 5 < i3 = 7.Bai 1

Program hoanvi;Uses crt;Const maxLS = 255;Var s,t:string; ls:integer; bo: array [1..maxLS] of boolean; i:integer; F:text;{-----------------------------------------------------------------------}Procedure hvi(n:integer);Var i:integer; c:char;Begin If (n = 0) then Begin Writeln(F,t); Exit; End; For i:=1 to ls do If bo[i] then Begin bo[i]:=False; t[n]:=s[i]; hvi(n-1); bo[i]:=True; End;

Page 7: bai tap BFS

End;{-----------------------------------------------------------------------}BEGIN Clrscr; Assign(F,'HVX.INP'); Reset(F); Read(F,s); Close(F); Assign(F,'HVX.OUT'); Rewrite(F); t:=s; ls:=length(s); For i:=1 to ls do bo[i]:=true; hvi(ls); Close(F);

END.Bai 2

Var B:array[1..100] of char;

n:integer;Procedure printresult;

Var j:integer;check:boolean; Begin check:=true; For j:=1 to n-1 do

if (B[j]='B') and (B[j+1]='B') then

check:=false; if check=true then

For j:=1 to n do write(B[j]); writeln; End;

Procedure done(i:integer);

Var j:char;

Begin

For j:='A' to 'B' do

Begin B[i]:=j;

if i=n then printresult

else done(i+1);

End; End;Begin write('n='); readln(n);

done(1);

readln;

End.Bai 3

program chia_day;

const

fi = 'CHIA.INP';

fo = 'CHIA.OUT';

var

n,k:integer;

a:array[1..10] of integer;

t:array[1..10] of integer;

dd:array[1..10] of byte;

s:longint;

{_}

procedure bt(i:integer);

var j:integer; f:text;

begin

if (i>n) then

begin

assign(f,fo); rewrite(f);

for i:=1 to k do

begin

for j:=1 to n do if dd[j] = i then write(f,a[j],#32);

writeln(f);

end;

Page 8: bai tap BFS

close(f); halt;

end;

for j:=1 to k do

if t[j]+a[i] <= s div k then

begin

t[j]:=t[j]+a[i]; dd[i]:=j;

bt(i+1);

t[j]:=t[j]-a[i]; dd[i]:=0;

end;

end;

{_}

procedure NoSolution;

var f:text;

begin

assign(f,fo); rewrite(f); writeln(f,'NO SOLUTION'); close(f);

end;

{_}

procedure enter;

var

f:text; i:byte;

begin

assign(f,fi); {$i-} reset(f);

if (ioresult<>0) then begin writeln('file not found'); readln; halt; end;

readln(f,n,k);

s:=0;

for i:=1 to n do begin read(a[i]); s:=s+a[i]; end;

close(f);

fillchar(t,sizeof(t),0); fillchar(dd,sizeof(dd),0);

end;

{_}

begin

enter;

bt(1);

NoSolution;

end

.Bai 4

program xau_con;

var

x,y:string;

{_}

procedure enter;

begin

readln(x);

readln(y);

end;

{_}

function solve:boolean;

var i,j:integer; find:boolean;

begin

for i:=1 to length(x) do

begin

find:=false;

for j:=1 to length(y) do

if x[i]=x[j] then begin delete(y,1,j); find:=true; break; end;

if (not find) then exit(false);

end;

exit(true);

end;

Page 9: bai tap BFS

{_}

procedure output;

begin

writeln(solve);

end;

{_}

begin

enter;

output;

end.Code bai 2

Program bai2;

const fi = 'AB.INP';

fo = 'AB.OUT';

Var B:array[1..100] of char;

n:integer;

f: text;

{---------------------------------------------}

Procedure In_kq;

Var j: integer;

kt: boolean;

Begin

kt:= true;

For j:=1 to n-1 do

if (B[j] = 'B') and (B[j+1] = 'B') then kt:=false;

if (kt = true) then

Begin

For j:=1 to n do

write(f,B[j]);

writeln(f);

end;

End;

{---------------------------------------------}

Procedure done(i:integer);

Var j:char;

Begin

For j:='A' to 'B' do

Begin

B[i]:=j;

if i=n then In_kq

else done(i+1);

End;

End;

{---------------------------------------------}

Begin

Assign(f,fi); Reset(f);

Read(f,n); Close(f);

Assign(f,fo); Rewrite(f);

done(1);

close(f)

End.Bài 1.

Cho đồ thị vô hướng G. Hãy tìm số thành phần liên thông của đồ thị.Hướng dẫn:

Thực hiện tìm kiếm từ đỉnh s bằng thhur tục DFS(s) hoặc BFS(s). Các đỉnh thăm được từ s phải cùng một vùng liên thông với s nên tất cả đỉnh này được ghi nhận với cùng một số hiệu vùng liên thông.Trong chương trình bên dưới, đồ thị được biểu diễn bằng ma trận kề a, mảng ghi nhận số hiệu vùng liên thông của các đỉnh là v và sv cho biết số lượng vùng liên thông.

Chương trình:program lien_thong_DFS;uses crt;const max=100;

Page 10: bai tap BFS

fi='STPLT.INP'; fo='STPLT.OUT';type m1=array[0..max] of integer; m2=array[1..max,1..max] of 0..1;var a:m2; v:m1; n,sv:integer;procedure input;var f:text; i,j,k:integer;begin assign(f,fi); reset(f); readln(f,n); fillchar(a,sizeof(a),0); for i:=1 to n do begin for j:=1 to n do read(f,a[i,j]); readln(f); end; close(f);end;procedure DFS(i:integer);var j:integer;begin for j:=1 to n do if (v[j]=0) and (a[i,j]=1) then begin v[j]:=sv; DFS(j); end;end;procedure Xuly; var s:integer;begin fillchar(v,sizeof(v),0); sv:=0; for s:=1 to n do if v[s]=0 then begin inc(sv); v[s]:=sv; DFS(s); end;end;procedure output;var f:text; i,j:integer;begin assign(f,fo); rewrite(f); writeln(f,sv); for i:=1 to sv do begin for j:=1 to n do if v[j]=i then write(f,j,' '); writeln(f); end; close(f);end;BEGIN input; Xuly; output; END.Trong chương trình trên nếu thay thủ tục DFS(s) bằng thủ tục BFS(s) kết quả hoàn toàn tương tự nhau.program lien_thong_BFS;uses crt; const max=100; fi='stplt.inp'; fo='stplt2.out';type m1=array[0..max] of integer; m2=array[1..max,1..max] of 0..1;var a:m2; v,q:m1; n,sv,dau,cuoi:integer; procedure input;var f:text; i,j,k:integer;

begin assign(f,fi); reset(f); readln(f,n); fillchar(a,sizeof(a),0); for i:=1 to n do begin for j:=1 to n do read(f,a[i,j]); readln(f); end; close(f);end;procedure empty;begin dau:=1; cuoi:=0;end;procedure add(s:integer);begin inc(cuoi); q[cuoi]:=s;end;procedure get(var s:integer);begin s:=q[dau]; inc(dau);end;procedure BFS(i:integer);var x,y:integer;begin empty; add(i); while (cuoi>=dau) do begin get(x); for y:=1 to n do if (a[x,y]=1) and (v[y]=0) then begin v[y]:=sv; add(y); end; end;end;procedure Xuly;var s:integer;begin fillchar(v,sizeof(v),0); sv:=0; for s:=1 to n do if v[s]=0 then begin inc(sv); v[s]:=sv; BFS(s); end;end;procedure output;

Page 11: bai tap BFS

var f:text; i,j:integer;begin assign(f,fo); rewrite(f); writeln(f,sv); for i:=1 to sv do begin for j:=1 to n do if v[j]=i then write(f,j,' ');

writeln(f); end; close(f);end;BEGIN input; Xuly; output;END.

.Bài 2.Ở trang trại của ông An, mỗi khi ông ngũ say là lúc sói đến ăn thịt cừu của ông.Trang trại hình chữ nhật gồm các ô được tổ chức thành hàng và cột. Trên bản đồ thể hiện trang trại có các kí hiệu: kí tự “.” là ô rỗng, kí tự “#” là hàng rào, kí tự “o” là cừu và “v” là chó sói.Hai ô được xem là cùng môt miền nếu ta di chuyển từ ô này sang ô khác bằng đường đi theo chiều ngang hoặc dọc và không có rào cản. Các ô mà từ đó có thể thoát khỏi trang trại không được xem là một phần của bất kì

miền nào. Cừu sẽ giết được sói nếu số lượng của chúng lớn hơn số lượng sói trong cùng miền. Ngược lại, sói sẽ ăn thịt tất cả cừu trong miền.Ban đầu, tất cả cừu và sói đều ở trong các miền của trang trại.Viết chương trình đếm số cừu và số sói còn sống sót vào buổi sáng hôm sau đó.

Dữ liệu vào:file văn bản SOICUU.INP gồm:- Dòng đầu chứa 2 số nguyên R và C, 3 ≤ R, C ≤ 250, là số dòng và số cột của trang trại.- Trong R dòng tiếp theo mỗi dòng C kí tự theo qui ước trong bản đồ trang trại cho biết vị trí của ô rỗng, rào cản, cừu và sói.Dữ liệu ra: file văn bản SOICUU.OUT gồm một dòng duy nhất chứa hai số, số cừu và số sói còn sống đến buổi sáng hôm sau.

Thí dụ:

SOICUU.INP SOICUU.OUT SOICUU.INP SOICUU.OUT

3 1 3 5

Hướng dẫn:Dùng thuật toán tìm kiếm xác định các miền liên thông. Trong mỗi miền liên thông đếm số cừu và số sói trong đó. Nếu số cừu lớn hơn số sói thì coi như số sói còn lại trong miền này bằng 0, ngược lại số cừu còn lại

trong miền này bằng 0. Khi tìm kiếm tới ô nào thì xóa ô đó bằng cách gán kí tự ‘#’ trên ô đó.Chương trình:program dem_soi_cuu;const MAXN = 500; MAXM = MAXN; MAXQ = MAXN*MAXM; fi='DEM.INP'; fo='DEM.OUT';var A : array[0..MAXN+1, 0..MAXM+1] of char; n, m, i, j, x, y, socuu, sosoi, tsosoi, tsocuu : longint; qx : array[0..MAXQ] of longint; qy : array[0..MAXQ] of longint; qp, qk : longint; f,g:text;procedure input;var i,j:integer;begin assign(f,fi); reset(f); readln(f,n,m); for i:=1 to n do begin for j:=1 to m do read(f,a[i,j]); readln(f); end; close(f);end;procedure push(x, y : longint);begin

qx[qp]:=x; qy[qp]:=y; if qp<MAXQ then qp:=qp+1 else qp:=0;end;procedure pop(var x, y : longint);begin x:=qx[qk]; y:=qy[qk]; if qk<MAXQ then qk:=qk+1 else qk:=0;end;procedure Duyet(x, y : longint);begin if A[x, y]<>'#' then begin push(x, y); if A[x, y]='v' then sosoi:=sosoi+1 else if A[x, y]='o' then socuu:=socuu+1; A[x, y]:='#'; end;end;begin input; qp:=0; qk:=0; tsosoi:=0; tsocuu:=0; for i:=1 to n do

Page 12: bai tap BFS

for j:=1 to m do if (A[i, j]='v')or(A[i, j]='o') then begin socuu:=0; sosoi:=0; Duyet(i, j); while qp<>qk do begin pop(x, y); Duyet(x+1, y); Duyet(x, y+1); Duyet(x-1, y);

Duyet(x, y-1); end; if socuu>sosoi then sosoi:=0 else socuu:=0; tsocuu:=tsocuu+socuu; tsosoi:=tsosoi+sosoi; end; assign(g,fo); rewrite(g); writeln(g,tsocuu, ' ', tsosoi); close(g);end.

Bài 3. Đường đi đến số 0Mỗi một số nguyên dương đều có thể biểu diễn dưới dạng tích của 2 số nguyên dương X,Y sao cho X<=Y. Nếu như trong phân tích này ta thay X bởi X-1 còn Y bởi Y+1 thì sau khi tính tích của chúng ta thu được

hoặc là một số nguyên dương mới hoặc là số 0. Ví Dụ : Số 12 có 3 cách phân tích 1*12, 3*4, 2*6. Cách phân tích thứ nhất cho ta tích mới là 0: (1-1)*(12+1) = 0, cách phân tích thứ hai cho ta tích mới 10: (3-1)*(4+1) = 10, còn cách phân tích thứ ba cho ta 7: (2-1)*(6+1)=7. Nếu như kết quả là khác không ta lại lặp lại thủ tục này đối với số thu được. Rõ ràng áp dụng liên tiếp thủ tục trên, cuối cùng ta sẽ đến được số 0, không phụ thuộc vào việc ta chọn cách phân tích nào để tiếp tục.Yêu cầu :Cho trước số nguyên dương N (1<=N<=10000), hãy đưa ra tất cả các số nguyên dương khác nhau có thể gặp trong việc áp dụng thủ tục đã mô tả đối với N. Dữ liệu vào : từ file văn bản ZERO.INP chứa số nguyên dương N.Kết quả : Ghi ra file văn bản ZERO.OUT: - Dòng đầu tiên ghi K là số lượng số tìm được - Dòng tiếp theo chứa K số tìm được theo thứ tự tăng dần bắt đầu từ số 0 .Lưu ý : Có thể có số xuất hiện trên nhiều đường biến đổi khác nhau, nhưng nó chỉ được tính một lần trong kết quả .Thí dụ :

ZERO.INP ZERO.OUT 12 6 0 3 4 6 7 10

Hướng Dẫn : Đơn giản là sau mỗi lần phân tích thì chắc chắn kết quả mới luôn nhỏ hơn số đó. Vì vậy ta chỉ cần lưu trữ dưới mảng A: [0..10000] of boolean ; trong đó A[i]=true nếu nó xuất hiện trên đường đi đó , ngợc lại thì

A[i]=false . Bằng cách loang theo chiều sâu, chúng ta sẽ đánh dấu các số nếu nó được dùng đến, cho đến khi không thể nào loang được nữa thì dừng .

Chương trình:

uses crt;

const tfi='ZERO.INP'; tfo='ZERO.OUT'; maxN=10000;var fi,fo: text; N: integer; dd: array[0..maxN] of byte;procedure Docdl;begin assign(fi,tfi); reset(fi); readln(fi,N); close(fi);end;procedure Loang(u: integer);var x,y: integer;begin if u>0 then begin for x:=1 to trunc(sqrt(u)) do if u mod x=0 then begin y:=u div x; if dd[(x-1)*(y+1)]=0 then begin dd[(x-1)*(y+1)]:=1; Loang((x-1)*(y+1)); end; end;

end;end;procedure Tim;begin fillchar(dd,sizeof(dd),0); Loang(N);end;procedure Inkq;var dem,sol,i: integer;begin sol:=0; for i:=0 to N do sol:=sol+dd[i]; assign(fo,tfo); rewrite(fo); writeln(fo,sol); dem:=0; for i:=0 to N do if dd[i]=1 then begin write(fo,i,' '); inc(dem); if dem mod 10=0 then writeln(fo); end; close(fo);end;

BEGIN Docdl; Tim; Inkq;END.

Page 13: bai tap BFS

Bài 4. Chuyển biCậu bé vẽ N (N<=100) vòng tròn, đánh số từ 1 tới N và tô màu các vòng tròn đó (có thể có các vòng tròn có màu giống nhau). Sau đó nối từng cặp lại bằng các cung định hướng, mỗi cung có một màu nhất định. Các

màu (của cung và của vòng tròn) được đánh số từ 1 đến 100.Cậu bé chọn 3 số nguyên khác nhau L, K và Q nằm trong phạm vi từ 1 tới N, đặt vào trong các vòng tròn số L và K mỗi vòng một hòn bi, sau đó bắt đầu di chuyển bi theo qui tắc sau:- Bi chỉ được chuyển theo cung có màu trùng với màu của vòng tròn chứa viên bi thứ 2.- Bi chỉ được chuyển theo chiều cung.- Hai viên bi không được đồng thời ở cùng một vòng tròn.- Quá trình di chuyển kết thúc, khi một trong hai viên bi tới vòng tròn Q.Hãy lập trình xác định cách di chuyển để chấm dứt quá trình sau một số ít nhất các bước chuyển.Dữ liệu: vào từ file BI.INP:- Dòng đầu: 4 số nguyên N, L, K, Q- Dòng thứ 2: N số nguyên C1, C2, …, CN (Ci: là màu của vòng tròn i).- Dòng thứ 3: số nguyên M (0<=M<=10000).- M dòng sau: mỗi dòng 3 số nguyên Ai Bi Di xác định cung màu Di đi từ vòng tròn Ai tới vòng tròn Bi. Các số trên một dòng cách nhau 1 dấu cách.Kết quả: đưa ra file BI.OUT:- Dòng đầu: YES hoặc NO cho biết quá trình có kết thúc được hay không.- Nếu dòng đầu là YES thì dòng 2 chứa số nguyên xác định số bước chuyển tối thiểu.Hướng dẫn:

Trong bài này ta xét một kỹ thuật tìm kiếm theo chiều rộng (loang) phát triển thêm đó là loang đổ mảng: trong quá trình loang, ta thường hay dùng một hàng đợi để lưu lại toàn bộ các trạng thái đã thăm và chuẩn bị thăm. Nhưng ta chú ý loang là tìm kiếm theo mức, từ một mức khởi đầu sẽ sinh ra mức tiếp theo và từ mức tiếp theo sẽ sinh ra mức tiếp theo nữa… Khi đó, mức đã được dùng để sinh không còn cần thiết nữa nghĩa là ta hoàn toàn có thể loại bỏ chúng ra khỏi hàng đợi để lấy "chỗ" cho các trạng thái sau. Từ ý tưởng trên, ta sẽ dùng 2 mảng khác thay thế cho 1 hàng đợi để lưu lại 2 mức liên tiếp nhau.

Ở bài tập này, một trạng thái được ghi nhận là số thứ tự của 2 vòng tròn chứa 2 viên bi và ta coi nó là một nút của cây tìm kiếm, ký hiệu (i,j).Gọi nhãn của một nút là f(i,j): f(i,j)=0 hoặc f(i,j)=1 cho biết nút đó chưa thăm hay đã thăm. Như vậy một nút sẽ được thăm nếu nó thỏa mãn mọi điều kiện của bài toán và nhãn của nó có giá trị 0. Từ đó, ta suy ra rằng

một mức sẽ có không quá n2 nút. Do vậy, ta sẽ dùng 2 mảng q1, q2 kích thước n*n để lưu lại các nút của 2 mức liên tiếp.

Chương trình:

const inp=’bi.inp’; out=’bi.out’;var a,q1,q2,f:array[1..100,1..100] of byte; c:array[1..100] of byte; n,v1,v2,v3:byte; m,dem:integer; stop:boolean; fi:text;

Procedure docf;var i,j,mau:byte; k:integer;begin

assign(fi,inp); reset(fi); readln(fi,n,v1,v2,v3);for k:=1 to n do read(fi,c[k]); readln(fi);

readln(fi,m); fillchar(a,sizeof(a),0);for k:=1 to m do

begin readln(fi,i,j,mau); a[i,j]:=mau;

end;close(fi);

end;

Procedure initBFS;begin

fillchar(f,sizeof(f),0) {khởi tạo tất cả các nút đều chưa thăm}

fillchar(q1,sizeof(q1),0){mức khởi đầu chưa có nút nào}fillchar(q2,sizeof(q2),0) {mức tiếp theo cũng chưa có nút

nào}q1[v1,v2]:=1;q1[v2,v1]:=1;

f[v1,v2]:=1;f[v2,v1]:=1;end;Procedure inkq;Begin writeln(fi,’YES’);

writeln(fi,dem);close(fi);halt;end;

Procedure play;var i,j,k:byte;begin

for i:=1 to n do for j:=1 to n do

if q1[i,j]=1 then for k:=1 to n do

if (k<>j) and (a[i,k]=c[j]) and (f[k,j]=0) then

begin q2[k,j]:=1;q2[j,k]:=1;

f[k,j]:=1;f[j,k]:=1; stop:=false; if k=v3 then inkq;

end;end;Procedure BFS;begin dem:=0; {bắt đầu ở mức 0}

repeat inc(dem); stop:=true;play;

if stop=false thenbegin

Page 14: bai tap BFS

q1:=q2; {ghi đè mức mới lên mức cũ}

fillchar(q2,sizeof(q2),0); {khởi tạo mức mới chưa có nút nào}

end;until stop;

Procedure xuly;begin

assign(fi,out); rewrite(fi); initBFS; BFS;writeln(fi,’NO’); close(fi);

end;

Begindocf;xuly;

End.

Thuật toán qui hoạch độngTrong quá trình học tập, chúng ta gặp rất nhiều các bài tập về Toán-Tin. Các bài tập dạng này rất phong phú và đa dạng. Thực tế chưa có thuật toán hoàn chỉnh có thể áp dụng cho mọi bài toán. Tuy nhiên người ta đã tìm ra một số thuật toán chung như chia để trị, tham ăn, quay lui,... Các thuật toán này có thể áp dụng để giải một lớp khá rộng các bài toán hay gặp trong thực tế. Trong bài viết này, tôi muốn đề cập với các bạn một thuật toán khác, đó là thuật toán quy hoạch động. Tư tưởng cơ bản của thuật toán là: Để giải một bài toán ta chia bài toán đó thành các bài toán nhỏ hơn có thể giải một cách dễ dàng. Sau đó kết hợp lời giải các bài toán con, ta có được lời giải bài toán ban đầu. Trong quá trình giải các bài toán con đôi khi ta gặp rất nhiều kết quả trùng lặp của các bài toán con. Để tăng tính hiệu quả, thay vì phải tính lại các kết quả đó, ta lưu chúng vào một bảng. Khi cần lời giải của một bài toán con nào đó ta chỉ cần tim trong bảng, không cần tính lại.Tư tưởng của thuật toán quy hoạch động khá đơn giản. Tuy nhiên khi áp dụng thuật toán vào trường hợp cụ thể lại không dễ dàng (điều này cũng tương tự như nguyên tắc Dirichlet trong toán vậy). Khi giải bài toán bằng phương pháp này, chúng ta phải thực hiện hai yêu cầu quan trọng sau:- Tìm công thức truy hồi xác định nghiệm bài toán qua nghiệm các bài toán con nhỏ hơn. - Với mỗi bài toán cụ thể, ta đề ra phương án lưu trữ nghiệm một cách hợp lý để từ đó có thể truy cập một cách thuận tiện nhất.Để minh hoạ thuật toán, ta xét một vài ví dụ.Ví dụ 1: Cho hai dãy số nguyên (a1,a2,...,am), (b1,b2,...,bn). Tìm dãy con chung có độ dài lớn nhất của hai dãy trên (coi dãy không có số nguyên nào là dãy con của mọi dãy và có độ dài bằng 0).Lời giảiChúng ta có thể thấy ngay rằng độ phức tạp của bài toán trên phụ thuộc vào hai số m, n. Xét hai trường hợp:+Trường hợp1:; m=0 hoặc n=0.Đây là trường hợp đặc biệt, có duy nhất một dãy con chung của hai dãy có độ dài  bằng 0. Vì vậy dãy con chung có độ dài lớn nhất của chúng có độ dài bằng 0. +Trường hợp 2: m# 0 và n # 0.Trong trường hợp này, ta xét các bài toán nhỏ hơn là tìm dãy con chung có độ dài lớn nhất của hai dãy (a1,a2,...,ai), (b1,b2,...,bj) với 0 <= i <= m, 0 <= j <= n. Gọi [i,j] là độ dài của dãy con chung lớn nhất của hai dãy (a1,...,ai), (b1,...,bj). ; Như vậy ta phải tính tất cả các l[i,j] trong đó 0<=i<=m, 0<=j<=n. Chúng ta có thể  thấy ngay rằng  l[0,0]=0. Giả sử ta tính được l[s,t] với 1        - Nếu ii # bj thì l[i,j]=max{l[i-1,j], l[i,j-1]}.        - Nếu ii=bj thì l[i,j]= 1+l[i-1,j-1].Với những nhận xét trên, ta hoàn toàn tính được l[m,n] chính là độ dài dãy con chung dài nhất của (a1,..am), (b1,..bn). Để tìm phần tử của dãy con, ta xuất phát từ ô l[m,n] tới ô l[0,0]. Giả sử ta đang ở ô l[i,j]. Nếu ai=bj thì ta thêm ai vào dãy con rồi nhảy tới ô l[i-1,j-1]. Nếu aibj thì l[i,j]=l[i-1,j] hoặc l[i,j]=l[i,j-1]. Nếu l[i,j]=l[i-1,j] thì nhảy tới ô l[i-1,j], ngược lại thì nhảy tới ô l[i,j-1].Sau đây là lời giải của bài toán. Chương trình được viết bằng ngôn ngữ Pascal:uses crt;  const fi='b2.inp';var a:array[1..10] of integer; b:array[1..10] of integer; kq:array[0..10,0..10] of integer; i,j,maxa,maxb:integer; f:text;procedure init;  begin  assign(f,fi); reset(f); i:=0;  while not(eoln(f)) do begin inc(i); read(f,a[i]); end; maxa:=i;  readln(f);

i:=0;  while not(eoln(f)) do begin inc(i); read(f,b[i]); end; maxb:=i;  close(f);  end;    function max(a,b:integer):integer;  begin  if a>b then max:=a else max:=b;  end; begin  init;  kq[0,0]:=0;  for i:=1 to maxa do for j:=1 to maxb do if a[i]<>b[j] then kq[i,j]:=max(kq[i-1,j],kq[i,j-1]) else kq[i,j]:=kq[i-1,j-1]+1;

Page 15: bai tap BFS

 writeln('Do dai day con chung lon nhat:',kq[maxa,maxb]);  i:=maxa; j:=maxb;  while (i>0)or(j>0) do if a[i]=b[j] then begin write(a[i]);

dec(i); dec(j); end else if kq[i-1,j]=kq[i,j] then dec(i) else dec(j);  end.

Với nội dung file ‘b2.inp’ chứa 2 dãy (a1,a2,..am) ,(b1,b2,..bn) sau:1 2 3 2 3 4 66 9 8 7Xét bài toán kinh điển về tối ưu tổ hợp:Ví dụ2: Cho cái túi chứa được trọng lượng tối đa là w. Có n đồ vật, đồ vật thứ i có khối lượng a[i] và giá trị c[i],  1<= i <=n. Tìm cách xếp đồ vật vào túi sao cho đạt giá trị lớn nhất.Lời giải Gọi f(k,v) là giá trị lớn nhất của túi đựng trọng lượng v và chỉ chứa các đồ vật từ 1 đến k.Nếu k=1 thì f(k,v)=(v div a[1])*c[1]. Giả sử tính được f(s,t) với 1<S< ti?nh Ca^`n 1<t Đặt: tg=v div a[k], f(k,v)=max{f(k-1,u)+x*c[k]}  (*) ,với x=0,1,2,...,tg, u=v-x*a[k]Giá trị lớn nhất là f(n,w). Ta dùng mảng bản ghi a[1..n,1..w] chứa kết quả trung gian. Mỗi bản ghi a[k,v] chứa giá trị f(k,v) và giá trị x thoả mãn công thức (*).Để xác định số lượng x[i] đồ vật i thoả mãn điều kiện tối ưu, ta xuất phát từ a[n,w] xác định được x[n]. Nhảy tới a[n-1,w-x[n]*a[n]] xác định được x[n-1]. Cứ như vậy tới x[1].uses crt;  const n=5; w=17; fi='b3.inp';  type kq=record num,val:integer; end;var a:array[1..10] of integer; {khoi luong} c:array[1..10] of integer; {Gia tri} i,j,tg,k,max,save:integer; f:text; b:array[1..n,1..w] of kq;procedure init;  begin  assign(f,fi); reset(f);  for i:=1 to n do begin read(f,a[i],c[i]); end;  close(f);end;begin  init;  for j:=1 to w do for i:=1 to n do

begin tg:=j div a[i]; max:=0; for k:=0 to tg do if (b[i-1,j-k*a[i]].val+k*c[i])>max then begin max:=b[i-1,j-k*a[i]].val+k*c[i]; save:=k; end; b[i,j].val:=max; b[i,j].num:=save; end;  for i:=1 to n do begin  for j:=1 to w do write(b[i,j].val:3); writeln; end;  writeln('Max:',b[n,w].val);  i:=n; j:=w;  while i>=1 do begin if b[i,j].num>0 then writeln('Co ',b[i,j].num,' do vat ',i); j:=j-a[i]*b[i,j].num; dec(i); end;  readln;end.

Với nội dung file ‘b3.inp’ :hàng i chứa khối lượng a[i], giá trị c[i]:3 44 57 108 119 13Qua hai ví dụ trên chắc các bạn đã nắm được tư tưởng của thuật toán qui hoạch động cũng như cách cài đặt cho nó. Như các bạn thấy, cách phát biểu thuật toán rất đơn giản. Nếu biết cách vận dụng thuật toán một cách hợp lý, ta có thể giải được một lớp khá rộng các bài toán trong thực tế. Hi vọng thuật toán sẽ là công cụ tốt của các bạn trong quá trình học tập môn tin học.Tập tin định kiểu Tập tin định kiểu là tập tin mà các phần tử (mẫu tin) của nó có cùng độ dài. Kiểu tập tin có thể là kiểu cơ sở như ký tự, nguyên, thực,... hoặc kiểu có cấu trúc như mảng, bản ghi,... 

Page 16: bai tap BFS

a. Cách khai báo + Khai báo gián tiếp TYPE <Kiểu File> = FILE OF <Kiểu phần tử> ; VAR <Biến File> : <Kiểu File> ; Ví dụ TYPE {Ðịnh nghĩa các kiểu tập tin} FileNguyen = FILE OF integer ; FileReal = FILE OF real ; FileKyTu = FILE OF char ; NhanSu = RECORD HoTen : string[25] ; Tuoi : Byte ; Dchi : string[35] ; Luong : real ; END ; FileNhanSu = FILE OF NhanSu ; VAR FN : FileNguyen ; FR : FileReal ; FC : FileKyTu ; FP : FileNhanSu ; + Khai báo trực tiếp VAR <Biến File> : FILE OF <Kiểu phần tử> ; Ví dụ TYPE NhanSu = RECORD HoTen : string[25] ; Tuoi : Byte ; Dchi : string[35] ; Luong : real ; END ; VAR FN : FILE OF integer ; FR : FILE OF real ; FC : FILE OF char; FP : FILE OF NhanSu ; Trong các ví dụ trên, ta có: - Biến tập tin FN là một tập tin kiểu nguyên với mỗi phần tử của chúng là một số nguyên và có độ dài là 2 bytes. - Biến tập tin FR là một tập tin kiểu thực với mỗi phần tử của chúng là một số thực và có độ dài là 6 bytes. - Biến tập tin FC là một tập tin kiểu ký tự với mỗi phần tử của chúng là một ký tự và có độ dài là 1 byte. - Biến tập tin FP là một tập tin kiểu bản ghi với mỗi phần tử của chúng là một bản ghi và có độ dài là 67 bytes. * Thủ tục ASSIGN(FileVar, FileName) Lệnh này dùng để gán tên tập tin FileName cho 1 biến file là FileVar. Filename là tên của một tập tin, do vậy FileName cần tuân theo cách đặt tên của MS-DOS. Ví dụ 8.48: VAR Fnguyen : FILE OF integer ; BEGIN ASSIGN(Fnguyen, ‘SONGUYEN.DAT ’) ; { Gán tập tin có tên là SONGUYEN cho biến Fnguyen } REWRITE(FileVar) {Cậu lệnh sẽ giải thích ở phần kế} ................ * Thủ tục REWRITE (FileVar) Lệnh này mở một tập tin mới trên đĩa từ có tên là FileName (đã khai báo trong thủ tục ASSIGN). Nếu FileName đã có sẵn trong đĩa thì nội dung của nó bị xóa và con trỏ đặt ở đầu tập tin. Trong cả 2 trường hợp, sau lệnh này trong tập tin đều rỗng và thông tin mới sẽ được đưa vào nhờ thủ tục WRITE sẽ trình bày ở phần sau. * Thủ tục RESET(FileVar) Mở tập tin có sẵn trong đĩa từ có tên là FileName đã khai báo trong lệnh ASSIGN, con trỏ tập tin đặt ở đầu tập tin, dùng lệnh READ để đọc thông tin (sẽ đề cập ở phần sau). * Thủ tục WRITE(FileVar, x1, x2, ..., xn) Lệnh này ghi lần lượt các biến x1, x2, ..., xn, là các biến thuộc kiểu phần tử của biến File, vào tập tin có tên là FileName (trong lệnh ASSIGN) vào đĩa từ theo ví trí tuần tự của con trỏ đang đứng. 

Page 17: bai tap BFS

* Thủ tục READ(FileVar, x1, x2, ..., xn) Lệnh này đọc tuần tự các giá trị x1, x2, ..., xn tại vị trí con trỏ đang đứng rồi gán vào các biến tương ứng cùng kiểu. Chú ý: Sau khi đọc hoặc ghi một phần tử, thì con trỏ tập tin sẽ di chuyển xuống vị trí phần tử tiếp theo. Ví dụ 8.49: Program Write_Read; Var Tepnguyen: File Of integer; i: integer; Begin Assign(tepnguyen,’U:\SONGUYEN.DAT ’); Rewrite(Tepnguyen); For i :=1 to 4 do write(tepnguyen,i); begin Read(tepnguyen,i); write(‘i= ‘,i:4); end; Close(Tepnguyen); Readln(tepnguyen); End. * Thủ tục SEEK(FileVar, n) Lệnh này chỉ thị con trỏ tập tin chuyển đến vị trí phần tử thứ n của tập tin. Trong đó, n là số nguyên chỉ vị trí các phần tử trong tập tin, phần tử thứ nhất có số thứ tự là 0. * Hàm EOF(FileVar):Boolean Hàm EOF (End-Of-File) này dùng để kiểm tra tình trạng hết tập tin. Nếu con trỏ ở cuối file thì nó sẽ cho kết quả là TRUE, ngược lại con trỏ ở bất kỳ nơi khác không phải ở cuối tập tin là FALSE. Mỗi ô là một phần tử của tập tin. Nếu con trỏ nằm ở vị trí cuối, EOF sẽ là TRUE. * Thủ tục CLOSE(FileVar) Ðóng tập tin lại và cập nhật thư mục để phản ánh tình trạng mới của tập tin. 3. Tập tin văn bản TOP 

a. Khái niệm Trong Pascal có một kiểu tập tin khác, đó là tập tin văn bản, có tên gọi là text file. Ðây là tập tin kiểu ký tự, tuy nhiên, tập tin text được cấu trúc thành các dòng, mỗi dòng được kết thúc bởi dấu hết dòng eoln (end-of-line). Ðối với Turbo Pascal, dấu eoln được tạo bởi 2 ký tự điều khiển là CR (carriage return - về đầu dòng) và LF (line feed - nhảy xuống dòng tiếp). CR là chr(13) và LF là chr(10). Text file được kết thúc bởi dấu end-of-file, với Turbo Pascal dấu end-of-file là Ctrl-Z có mã ASCII là ký tự số 26. Vì chiều dài của các dòng là khác nhau nên tập tin văn bản chỉ có thể truy xuất theo kiểu tuần tự. Ngoài ra, không thể tiến hành cả 2 hoạt động đọc và ghi cùng lúc trên text file. Ðể sử dụng text file, ta phải thực hiện các thủ tục ASSIGN, sau đó mở tập tin bằng các thủ tục RESET, REWRITE hoặc APPEND. - REWRITE dùng để tạo ra một text file mới, sau đó ta chỉ có thể tiến hành ghi lên text file một cách tuần tự. - RESET để mở một tập tin đã có và sau đó ta chỉ có thể đọc một cách tuần tự. * Ghi dữ liệu vào tập tin văn bản Có 3 mẫu để ghi dữ liệu vào text file là: • WRITE(FileVar, Item1, Item2, ..., ItemN) ; Ghi giá trị các phần tử Item1, Item2,..., ItemN lên tập tin được đại diện bởi FileVar. • WRITELN(FileVar, Item1, Item2, ..., ItemN) ; Giống như thủ tục WRITE, nhưng sau đó sẽ ghi thêm dấu kết thúc dòng (các ký tự điều khiển: CR và LF) • WRITELN(FileVAR) ; Chỉ làm một việc là ghi lên tập tin dấu kết thúc dòng. FileVar là một biến kiểu text. Item1, Item2, ..., ItemN là các mục ghi các hằng, biến, biểu thức của các kiểu vô hướng chuẩn, kiểu miền con và kiểu chuỗi. Các thủ tục ghi vào text file không chấp nhận các kiểu ghi dữ liệu kiểu mảng (ARRAY), kiểu tập hợp (SET), kiểu bản ghi (RECORD) và kiểu tập tin (FILE). Ví dụ Program TepVanban; Var f: TEXT; Begin Assign(f,’U:\Vanban.DAT’); Rewrite(f); (1) Writeln(f,1,2,3); (2) write(f,4,5); (3) writeln(f); (4) Close(f); End. Chương trình sẽ tạo ra tệp U:\Vanban.Dat có dạng như sau: * Ðọc dữ liệu từ tập tin văn bản: Việc đọc dữ liệu từ tệp văn bản được thực hiện hoàn toàn tương tự như việc đọc dữ liệu từ bàn phím, ta có 3 mẫu để đọc dữ liệu từ text file là: - READ(FileVar, Variable1, Variable2, ..., VariableN) ; 

Page 18: bai tap BFS

- READLN(FileVar, Variable1, Variable2, ..., VariableN) ; - READLN(FileVAR) ; FileVar là một biến kiểu text. Variable1, Variable2, ..., VariableN là các biến thuộc các kiểu vô hướng chuẩn, kiểu miền con và kiểu chuỗi. Thủ tục Readln(FileVar, Variable1, Variable2, ..., VariableN) ; sẽ đưa con trỏ xuống hàng tiếp sau khi đọc hết các biến tương ứng. Thủ tục Readln(FileVar) ; xuống dòng tiếp theo mà không đọc gì hết. Các thủ tục đọc dữ liệu từ text file không chấp nhận các dữ liệu kiểu mảng (ARRAY), kiểu tập hợp (SET), kiểu bản ghi (RECORD) và kiểu tập tin (FILE). Ví dụ Chương trình đếm số dòng của một tệp văn bản: Program Dem_dong; Var f:TEXT; sodong:integer; Begin sodong:=0; {$I-} Assign(f,’U:\VanBan.DAT’); Reset(f); {$I+} if IOResult<>0 then begin Writeln(' Tệp này không tồn tại '); halt(1); end esle begin While Not EOF(f) Do begin INC(sodong); readln(f); {Xuống dòng kế tiếp} end; Close(f); Writeln(' Số dòng đã đếm được là :' ,sodong); Readln; End. * Hàm EOLN(FileVar) Hàm EOLN(f) có giá trị là true nếu như con trỏ của text file f đang ở vào ký tự điều khiển CR của dấu end-of-line hoặc khi end-of-file có giá trị là true.

inc(i) là dùng để tăng biến đó thêm 1 đơn vịinc(i,n) {n là số bạn chọn} là để tăng biến đó lên n đơn vị

*

 Dời qua bên trái k bit: SHL