Tải bản đầy đủ - 0 (trang)
Kết quả: Đưa ra file văn bản TRAVEL.OUT:

Kết quả: Đưa ra file văn bản TRAVEL.OUT:

Tải bản đầy đủ - 0trang

 Phân rã việc xử lý thành dãy các công việc đơn giản hơn hoặc tác

động lên một bộ phận dữ liệu (giảm kích thước bài tốn),

 Ngun lý: tháo gỡ khó khăn chứ khơng phải đẩy lùi khó khăn

xuống mức sau!

Sản phẩm chương trình ở bước 1 có dạng:

Program VD3_ThKe_CT;

Const fi



=



'TRAVEL.INP';



fo



=



'TRAVEL.OUT';



Type



maxN =



10000;



link



=



^node;



node



=



record



point



:



longint;



next



:



link;



f, g



:



Text;



dsk



:



array[1..maxN] of link;



N, m



:



longint;



d



:



array[1..maxN] of longint;



kq



:



array[1..maxN,1..2] of longint;



end;

Var



Begin

Mo_file;

Nhap;

Tim_hanhtrinh;

Ghinhkq;

Dong_file

End.

o Bước 2: Chi tiết hóa các cơng việc ở bước 1. Ở đây ta chỉ quan tâm

sâu đến Tim_hanhtrinh;



23



Procedure

Var



Tim_hanhtrinh;



i, j, k, x, sl



:



longint;



pp, pp2



:



link;



Begin

for i:=1 to N do

Begin

Khoitao;

Duongtu(i);



{khoi tao truoc khi xet moi dinh i}

{tim chu trinh 4 dinh xuat phat tu i va tro ve i}



end;

end;

Thủ tục Duongtu(i) sẽ thực hiện xử lý lần lượt với mỗi nút i. Chúng

ta cũng gần như chưa làm gì cả, nhưng đã đưa được bài tốn tìm với n

phần tử về bài tốn tìm với 1 phần tử. Nhiệm vụ cần thực hiện trở nên đơn

giản hơn. Trong thủ tục trên ta mới sử dụng có một dữ liệu vào (giá trị n).

o Bước 3: Chi tiết hóa việc xử lý đường đi từ đỉnh i.

Ở đây, với mỗi nút i, coi nút i là gốc. Từ gốc i sẽ lần lượt tìm đến các

con bậc 1 là J, với mỗi J sẽ tìm đến các con bậc 2 là K. Với mỗi con k bậc

2, mỗi lần thăm sẽ đánh dấu lại là đã thăm một lần và lần thăm đó là thơng

qua con J bậc 1. Khi đó nếu như có 2 lần thăm con K bậc 2 sẽ dẫn tới tồn

tại 2 con bậc 1 là J1 và J2 khác nhau sao cho có cung nối từ I  J1  K

và từ I  J2  K. Suy ra 4 đỉnh I, J1, K, J2 sẽ tạo thành một chu trình

khép kín theo như u cầu của bài toán.

Procedure



Duongtu(i:longint);



Begin

pp:=dsk[i];

while pp<>nil do

Begin

j:=pp^.point;



{j la con bac 1 cua i}



Conbac2(i);

24



pp:=pp^.next;

end;

End;

Thủ tục Conbac2(i); sẽ duyệt qua các con bậc 2 cuả i .

o



Bước 4: Chi tiết hóa việc duyệt con bậc 2 để ghi nhận và kiểm tra

kết quả.



Procedure



Conbac2(i: longint);



Begin

pp2:=dsk[j];

while pp2<>nil do

Begin

k:=pp2^.point;

if k<>i then luu_kiemtra(k);

pp2:=pp2^.next;;

end;

End;

Thủ tục luu_kiemtra(k); để xét với mỗi con K bậc 2 của i, ta sẽ

dùng dữ liệu để dánh dấu giúp cho việc duyệt qua lại tốn ít thời gian và có

thể lấy được ngay kết quả.

o Bước 5: Chi tiết hóa việc ghi nhận con K bậc 2 của i và kiểm tra

kết quả.

Procedure



Luu_kiemtra(k:longint);



Begin

inc(d[k]);



{tang so lan tham cua dinh k}



kq[k,d[k]]:=j;



{duong di den k qua j}



if d[k]=2 then



{ neu k da duoc tham 2 lan thi xuat kq}



Ghiduongdi;

end;



25



Tuy thủ tục Ghiduongdi là đơn giản nhưng chúng ta vẫn dẫn xuất

nó ở đây:

o Bước 6: Nếu có kết quả thì ghi và kết thúc.

Procedure Ghiduongdi;

Begin

writeln(g,i,' ',kq[k,1],' ',k,' ',kq[k,2]);

Dong_file;

halt;

End;

Với việc dùng mảng luu ta có thể xuất ngay được kết quả.

****Tồn bộ chương trình****

Program



VD3_ThKe_CT;



Const fi



=



'TRAVEL.INP';



fo



=



'TRAVEL.OUT';



maxN =



10000;



link



=



^node;



node



=



record



point



:



longint;



next



:



link;



f, g



:



Text;



dsk



:



array[1..maxN] of link;



N, m



:



longint;



d



:



array[1..maxN] of longint;



kq



:



array[1..maxN,1..2] of longint;



Type



end;

Var



Procedure



Mo_file;



Begin

assign(f,fi); reset(f); assign(g,fo); rewrite(g);

26



end;

Procedure



dong_file;



Begin

close(f); close(g);

end;

Procedure

Var



Nhap;



i, x, y :



longint;



pp



link;



:



Begin

readln(f,N,M);

for i:=1 to M do

Begin

readln(f,x,y);

new(pp);

pp^.point:=x;

pp^.next:=dsk[y];

dsk[y]:=pp;

new(pp);

pp^.point:=y;

pp^.next:=dsk[x];

dsk[x]:=pp;

end;

end;

Procedure



khoitao;



Begin

fillchar(d, sizeof(d),0);

fillchar(kq, sizeof(kq),0);

End;



27



Procedure



Ghiduongdi;



Begin

writeln(g,i,' ',kq[k,1],' ',k,' ',kq[k,2]);

Dong_file;

halt;

End;

Procedure



Luu_kiemtra(k:longint);



Begin

inc(d[k]);

kq[k,d[k]]:=j;

if d[k]=2 then

Ghiduongdi;

end;

Procedure



Conbac2(i: longint);



Begin

pp2:=dsk[j];

while pp2<>nil do

Begin

k:=pp2^.point;

if k<>i then luu_kiemtra(k);

pp2:=pp2^.next;;

end;

End;

Procedure



Duongtu(i:longint);



Begin

pp:=dsk[i];

while pp<>nil do

Begin

j:=pp^.point;



{j la con bac 1 cua i}

28



Conbac2(i);

pp:=pp^.next;

end;

End;

Procedure

Var



Tim_hanhtrinh;



i, j, k, x, sl



:



longint;



pp, pp2



:



link;



Begin

for i:=1 to N do

Begin

Khoitao;



{khoi tao truoc khi xet moi dinh i}



Duongtu(i);



{tim chu trinh 4 dinh xuat phat va ve tu i}



end;

end;

Procedure Ghinhkq;

Begin

writeln(g,-1);

End;

Begin

Mo_file;

Nhap;

Tim_hanhtrinh;

Ghinhkq;

Dong_file;

End.



29



VÍ DỤ 4. BẢN VANXO FIBONACCI (Đề thi HSG Quốc Gia 2012)

Bản vanxơ Fibonacci là một bản nhạc mà giai điệu của nó bắt

nguồn từ một trong những dãy số nổi tiếng nhất trong Lý thuyết số - dãy số

Fibonacci. Hai số đầu tiên của dãy là số 1 và số 2, các số tiếp theo được

xác định bằng tổng của 2 số liên tiếp ngay trước nó trong dãy.

Bản vanxơ Fibonacci thu được bằng việc chuyển dãy số Fibonacci

thành dãy các nốt nhạc theo qui tắc chuyển một số nguyên dương thành nốt

nhạc sau đây:

Số 1 tương ứng với nốt Đô (C).

Số 2 tương ứng với nốt Rê (D).

Số 3 tương ứng với nốt Mi (E).

Số 4 tương ứng với nốt Fa (F).

Số 5 tương ứng với nốt Sol (G).

Số 6 tương ứng với nốt La (A).

Số 7 tương ứng với nốt Si (B).

Số 8 tương ứng với nốt Đô (C).

Số 9 tương ứng với nốt Rê (D).

và cứ tiếp tục như vậy.

Ví dụ, dãy gồm 6 số Fibonacci đầu tiên 1, 2, 3, 5, 8 và 13 tương ứng với

dãy các nốt nhạc C, D, E, G, C và A.

Để xây dựng nhịp điệu vanxơ người ta đi tìm các đoạn nhạc có

tính chu kỳ trong bản vanxơ Fibonacci. Đoạn nhạc được gọi là có tính chu

kỳ nếu như có thể chia nó ra thành k ≥ 2 đoạn giống hệt nhau. Ví dụ, đoạn

nhạc GCAGCA là đoạn có tính chu kỳ, vì nó gồm 2 đoạn giống nhau

GCA.

Yêu cầu: Cho trước hai số nguyên dương u, v (u < v), hãy xác định độ dài

đoạn nhạc dài nhất có tính chu kỳ của bản nhạc gồm dãy các nốt nhạc của

bản vanxơ Fibonacci bắt đầu từ vị trí u kết thúc ở vị trí v.

Ràng buộc: 50% số tests ứng với 50% số điểm có ui < vi ≤ 100.

30



Dữ liệu: Vào từ file văn bản FIBVAL.INP:

• Dòng thứ nhất chứa số ngun dương k (k ≤ 100) là số lượng test.

• Dòng thứ i trong số k dòng tiếp theo chứa 2 số nguyên dương ui, vi

được ghi cách nhau bởi dấu cách (ui < vi ≤ 10 9) là vị trí bắt đầu và

kết thúc của 1 bản nhạc.

Kết quả: Đưa ra file văn bản FIBVAL.OUT:

• Ghi ra k dòng, dòng thứ i chứa 1 số nguyên là độ dài đoạn nhạc tìm

được tương ứng với test thứ i. Nếu khơng tìm được đoạn nào có tính

chu kỳ thì ghi ra số -1.

Ví dụ:

FIBVAL.INP

2



FIBVAL.OUT

-1



13



2



4 10

Phân tích:

• Lớp giải thuật:

o Duyệt

o Ngun lý: Khơng duyệt tồn bộ mà duyệt dựa vào tính chất chu kì

( lặp lại ) của bản nhạc

• Cấu trúc dữ liệu:

F:array[0..15] of longint=(1,1,2,3,5,1,6,0,6,6,5,4,2,6,1,0);

Mảng lưu lại chu kì lặp của dãy van xơ fibonaxi sau khi mã hóa nốt

nhạc thành số

• Thiết kế chương trình:

o Bước 1:

 Liệt kê các công việc, các bước bắt buộc phải thực hiện,

 Phân rã việc xử lý thành dãy các công việc đơn giản hơn hoặc tác

động lên một bộ phận dữ liệu (giảm kích thước bài tốn),

 Ngun lý: tháo gỡ khó khăn chứ khơng phải đẩy lùi khó khăn

xuống mức sau!

31



Sản phẩm chương trình ở bước 1 có dạng:

uses math;

Const fi

fo



=



'FIBVAL.INP';



=



'FIBVAL.OUT';



F : array[0..15] of longint=(1,1,2,3,5,1,6,0,6,6,5,4,2,6,1,0);

Var



f, g



:



Text;



u,v,x,y,t,i :



longint;



a



:



array[1..100] of longint;



s



:



string;



Begin

Mo_file;

readln(f, T);

for i:=1 to T do

Begin

Nhap;

Chuky;



{tim do dai chu ky ung voi test}



Ghinhkq;

end;

Dong_file;

End.

o Bước 2: chi tiết hóa các cơng việc ở bước 1. Ở đây chúng ta chỉ

quan tâm sâu đến thủ tục Chuky;

Thủ tục Chuky; đóng vai trò quan trọng nhất, nó phân bài tốn

thành 2 trường hợp dữ liệu bé và dữ liệu lớn. Tùy vào kích thước dữ liệu

mà đưa ra các xử lý khác nhau cho bài toán. Với kích thước lớn, đơn giản

là ta sẽ lấy ngay giá trị lặp lại của 16 nút fibo tuần hoàn (trong mảng

F).Nếu như kích thước bé thì ta hồn tồn có thể duyệt tồn bộ tất cả các

trường hợp rồi so sánh với cực đại.

Procedure



Chuky;

32



Begin

if (v-u+1)>=16*2 then

Begin

writeln(f,((v-u+1) div 16)*16 );

end

else kichthuocbe(u,v);

end;

Ở đây, thủ tục kichthuocbe(u,v); xử lý với kích thước của dãy số bé.

o Bước 3: Chi tiết hóa thủ tục giải quyết với kích thước bé.

Procedure

Var



kichthuocbe(u ,v : longint);



i,j,N, kq



:



longint;



ok



:



boolean;



ss



:string;



Begin

kq:=-1;

Vanxo(u,v,s);



{S chua ban nhac tu u den v}



N:=length(S);

for i:=1 to N do

for j:=i+1 to N do

Begin

ok := Kiemtra(i,j);



{kiem tra day con tu i den j co la chu ky}



if ok then kq:=max(kq,j-i+1); {so sanh de lay Kq tot hon}

end

end;

o Bước 4: Chi tiết hóa với thủ tục Vanxo(u,v,s) xây dựng xâu S chưa

bản nhạc từ u đến v và hàm Kiemtra(i,j); để kiểm tra dãy con từ u

đến v có là chu kỳ không.

procedure



Vanxo(u,v :longint; var s: string);



Begin

33



Tài liệu bạn tìm kiếm đã sẵn sàng tải về

Kết quả: Đưa ra file văn bản TRAVEL.OUT:

Tải bản đầy đủ ngay(0 tr)

×