1. Trang chủ
  2. » Công Nghệ Thông Tin

Thuật toán quay lui

5 1,9K 54
Tài liệu đã được kiểm tra trùng lặp

Đang tải... (xem toàn văn)

THÔNG TIN TÀI LIỆU

Thông tin cơ bản

Định dạng
Số trang 5
Dung lượng 67,5 KB

Nội dung

Thuật toán quay lui

Trang 1

Khử quay lui và bài toán từ đẹp

Lương Công Hảo

Sau khi đọcxong bài "Một số bài toán tin khó" của thầy Nguyễn Xuân Huy và thầy Hồ Sỹ

Đàm và các số báo của TH&NT viết về Giải Thuật Quay lui và khử Quaylui của các tác

giả: Chu Đức Minh, Nguyễn Văn Trường, Nguyễn Duy Hàm,Trương Thị Thu Hường…đã

nói rất rõ về giải thuật này Song đểvận dụng và giải quyết một số bài toán (như bài toán

"Từ đẹp" ) thì quả thật là khó khăn Nhằmgiúp các em học sinh hiểu thấu đáo hơn, tôi xin

mạnh dạn đưa ra cácý kiến sau mong các em học sinh và các bạn đồng nghiệp tham khảo gópý

Xuất pháttừ bài toán: Viết tất cả các dãy có độ dài n từ các ký tự A,B, C(chẳng hạn với

n=3, ta có: AAA, AAB, AAC, ) Để giải quyết bài toánnày ta chỉ cần dùng 3 vòng lặp For(n=3) là được Song với n lớn thì sao? Nếu giải quyết bài toán nàybằng quay lui, ta có thủ tục sau:

hellip;

m=’ABC’

hellip;

proceduretry(i:integer);

varj:integer;

begin

for j:=1 to3 do

begin

x[i]:=m[j];

if i=n theninkq esle try(i+1);

end;

try(1);

Trang 2

Từ mô hìnhtrên ta thấy:

- Khi gọi Try(i+1) mức tănglên 1

- Khi lùi mức giảm 1

- Và giảm đến mức 1

Như vậy,để tránh việc tràn Stack, ta có thể khử quay lui nếu biết tổ chức vàlưulại các giá trị đề cử j Để lưu j ứng với các mức của i ta dùngmảng a: array[1 n+1] of byte với a[i]=i (tại mỗi thời điểm) (xuất pháta[i]=1, i=1 n) Sau mỗi lần đề cử được tăng j ta tăng

a[i]:=a[i]+1, nếua[i] vượt quá giá trị đề cử ta gán a[i]:=1 Việc thay đổi này cóthể đặt trong hàm Đề cử (decu) hoặc trong thủ tục khử quay lui(khu_try)

Trong bàitoán này, hàm decu rất đơn gảin vì các khả năng của j đều chấp nhậnđược vì không có ràng buộc nào Để lưu nghiệm ta dùng biến string(nhược điểm: dài tối đa 256)

Sau đây là văn bản chươngtrình:

Programkhu_quay_lui;

Const n=3;

Varx,y:string ;

A:array[1 300] of byte;

I:integer;

Procedureinkq;

Begin

Writeln(x);

End;

Functiondecu(i:integer):integer;

Varj:integer;

Begin

Decu:=0;

For j:=a[i]to 3 do

Begin

Decu:=j;

Exit;

End;

End;

Procedurekhu_try;

Varj:integer;

Stop:boolean;

Begin

Stop: false;

While notstop do

Begin

Repeat

J:=decu(i);

If j>0then

Begin

X:=x+y[j];

I:=i+1;

If i>nthen begin inkq; j:=0; end;

If a[i]>3then a[i]:=1;

Trang 3

End;

Until j=0;

I:=i-1;

If i>0then begin a[i]: a[i] +1; delete(x,i,1);

End elsestop:=true;

End;

End;

Begin

Y:=’ABC’;

For i:=1 ton do a[i]:=1;

I:=1;

X:=’’;

Khu_try;

Readln;

End

Từ bài toántrên ta có thể phát triển để giải quyết bài "Từ đẹp" (Bài 3a − Tìm chuỗi có độ dài n xây dựng từ các ký tự A,B,Csao cho không có 2 chuỗi con liên tiếp giống nhau), với

các bổ xungsau:

- Viết thêm hàm KT: kiểmtra xem chuỗi có 2 chuỗi con liên tiếp hay không?

- Dùng mảng x: array[1 n]of char để lưu kết quả (để có độ dài lớn)

- Không duyệt tất cả cácdãy mà chỉ cần tìm một nghiệm đầu tiên (đặt exit trong lệnh kiểmtra đủ cấu hình)

Do chỉ tìmmột nghiệm đầu tiên nên chương trình chạy tương đối nhanh, vớin=700 khoảng

1 giây, với n=10000 khoảng 2 phút (nếu dùng quay lui chỉ chạyđược với n≤29, nếu có dẫn biên dịch {$M65520,0,655360} thì n≤123)

Sau đây là văn bản chươngtrình:

ProgramKhu_quay_lui_bai_tu_dep;

{$R-}

const n =10000;

typechuoi=array[1 10001] of char;

var

a:array[1 10001]of byte;

c,y: chuoi;

m:string[3];

i:integer;

functionkt(l:integer):boolean;

vart,k,m,d,c,c1:integer;

begin

kt:=true;

for t:=1 totrunc(1/2) do

begin

d:=1-2*t+1;

c:=1-t+1;

c1:=c;

m:=0;

Repeat

Trang 4

If y[d]=y[c]then m:=m+1;

D:=d+1;c:=c+1;

If m=t thenbegin kt:=false; exit; end;

Until d=c1;

End;

End;

Functiondecu(k:integer):integer;

Varz:integer;

Begin

Decu:=0;

For z=1 to ndo y[z]:=��;

For z:=1 tok-1 do y[z]:= c[z];

For z:=a[k]to 3 do

Begin

Y[k]:=m[z];

A[k]:=a[k]+1;

If kt(k)then

Begin

Decu:=z;

Exit;

End;

End;

End;

Procedureinkq(var q:chuoi);

Varj:integer;

Begin

For j:=1 ton do write(q[j]);

Writeln;

End;

Proceduretry;

Varj,k:integer;

Begin

Repeat

Repeat

J:= decu(j);

If j>0then {chap nhan j}

Begin

C[i]:=m[i];

If (i=n)then

Begin

Exit; {thoatkhong ghi nhan duoc nghiem dau tien} {inkq(c);

if a[i]>3then begin a[i]:=1;j:=0; end;}

end else

i:=i+1;

if (i>n)then j:=0;

Trang 5

end

else ifa[i]>3 then begin a[i]:=1; end;

until (j=0);

i:=i-1;

if (i>0)then

begin

if(a[i]>3) then begin a[i]:=1;i:=i-1; end;

end;

until i=0;

end;

Begin

Fillchar(c,sizeof(c),’’);

For i:=1 ton do a[i]:=1;

M:=’ABC’;

I:=1;

Try;

Writeln(’Chuoican tim la:’);

Inkq(c);

Readln;

End

*) Rõ ràng tađã biết, với 2 chữ cái thì bài toán "Từ đẹp " sẽ vô nghiệm khin ≥4 Vì với n=3

ta chỉ có 2 nghiệm là ABA và BAB, do chỉ có 2 khảnăng đề cử là A hoặc B nên không thể thêm vào được nữa để sinhchuỗi có độ dài lớn hơn 3 (thêm vào sẽ vi phạm luật "đẹp

"ngay)

Với 3 chữ cái thì bài toán có nghiệm với mọi nnguyên dương Vì có thể dựa vào 2 yều tố sau:

Theokết quả từ chương trình, khi n càng lớn thì số từ đẹp càng tăngnhanh Ví dụ: n=2 (có 6 nghiệm), n=3 (có 12 nghiệm), n=4 (có 18 nghiệm),n=5 (có 30 nghiệm), n=6 (có 42

nghiệm), n=7 (có 60 nghiệm), n=8 (có 78nghiệm), n=9 (có 108 nghiệm),&hưellip; Giảsử ta

đã xây dựng được từ đẹp có độ dài n≥2 - Nếu n chẵn thì bao giờcũng thêm được một ký tự (khác với ký tự cuỗi hoặc áp cuỗi) vàosau để được từ đẹp có độ dài n+1

- Những từ đẹp có độdài n+1 (lẻ) nếu không phải dạng "đối xứng gánh " cũng đều cóthể thêm vào ký tự cuỗi để được từ đẹp mới

Ví dụ từ đẹp "đối xứng gánh ": ACABACA khôngthể thêm vào 1 ký tự nào nữa, nhưng không phải tất cả các nghiệmđều có dạng này

*) Nếu thêm ràngbuộc "Bài 3b − cố định một chữ cái x, tìm từ đẹp có chiều dài n

saocho số lần xuất hiện của ký tự x là ít nhất " thì ta phải duyệt tất cả các từ đẹp và với

mỗi nghiệm ta đếmsố ký tự x (đếm khi xây dựng nghiệm), sau đó dùng thêm thủ

tụcTimKetQua để ghi nhận kỷ lục (số lần xuất hiện ký tự ít nhất)

*) Về nhậnđịnh "Nếu bài toán 3a giải được thì bài toán 3b cũng giải đượcvà ngược lại ", theo tôi nhận xét như sau: Về mặt lý thuyết thì hiểnnhiên nhận định trên đúng nhưng thực

tế chỉ đúng với n nhỏ, cònn lớn thì bài toán 3b không thể giải quyết được (với n

khoảng10000?)

Ngày đăng: 11/09/2012, 15:00

TỪ KHÓA LIÊN QUAN

w