Thuật toán hiệu quả giải bài toán Mã đi tuần

3 6.5K 99
Thuật toán hiệu quả giải bài toán Mã đi tuần

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

Thông tin tài liệu

Thuật toán hiệu quả giải bài toán Mã đi tuần

Thuật toán hiệu quả giải bài toán đi tuầnNguyễn Văn TrungHẳn các bạn học lập trình pascal đã biết đến bài toán ″Mã đi tuần″: Cho bàn cờ tổng quát nxn và một quân mã. Hãy chỉ ra một hành trình của xuất phât từ ô (x,y), đi qua tất cả các ô còn lại của bàn cờ, mỗi ô đúng một lần (luật đi của như luật cờ vua). Và hẳn bạn đã biết thuật giải củabài toán này. Đó là dùng kỹ thuật duyệt quay lui xét các ô con. có thể đi tới để tìm ra một hành trình. Tuy nhiên, việc duyệt như vậy là hết sức chậm bởi phải xét quá nhiều trường hợp. Và với thuật toán như vậy, khi kích thước bàn cờ vượt quá 8(n>8) thì có thể nói bạn sẽ phải ngồi chờ đợi máy tính cho đến khi mất hết kiên nhẫn. Vì vậy mục đích của bài toán này là nêu ra một thuật giải hiệu quả hơn cho bài toánđi tuần. Ta coi bàn cờ nxn như một đồ thị vô hướng và thừa nhận ô (i,j) của bàn cờ là đỉnh (i-1xn+j) của đồ thị. Ví dụ: ô (1,n) là đỉnh thứ (1-1)xn+n=n của đồ thị ô (2,3) của bàn cờ 3x3 là đỉnh thứ (2-1)x3+3 = 6 của đồ thị. Như vậy việc tìm hành trình để con đi hết các ô của bàn cờ ↔ Tìm ra một hành trình đi hết các đỉnh của đồ thị, mỗi đỉnh chỉ đi qua một lần. +) Việc kiểm tra xem từ đỉnh u có thể tới đỉnh v hay không ta có thể thấy như sau: Giả sử ô(x1,y1) có đỉnh ở đồ thì là u → (x1 -1)xn +y1 =u Dễ thấy nếu (u mod n =0) thì x1 = u div n; y1 =n Còn nếu (u mod n <>0) thì x1 = u div n -1, y1 =u mod n. (Bạn có thể thấy nếu vẽ hình ra) Có hai cách để chúng ta tìm ra xem hai đỉnh u và v có thể đi đến từ nhau hay không: - Dùng mảng để lưu lại (mảng logic), như vậy nhanh hơn nhưng do không gian nhớ hạn chế của Pascal, nếu ta khai báo b[1 nxn,1 nxn] thì sẽ không thể giải khi n >10. - Vậy ta sẽ viết 1 hàm kt(u,v) kiểu boolean xem từ u có thể tới v không. Đoạn như sau. Function kt(u,v:integer):boolean; Var x1,x2,y2,y1:integer; Begin x1:= (u-1)div n +1; If u mod n =0 then y1:=n Else y1:=u mod n; X2:=(v-1) div n+1; If v mod n =0 then y2:=n Else y2:=u mod n; Kt:= (abs (x1-x2)*abs(y1=y2)=2); End; +) Khác với cách duyệt xét tất cả các ô có thể đến từ ô đang đứng, ở đây ta chỉ xét và chọn ô để đi tiếp theo từ ô đang đứng khi bậc của ô đó là nhỏ nhất. (Ta gọi bậc của ô (x,y) là số ô có thể đến từ sô này chưa hề đi qua). Như vậy số bậc của đỉnh u là số đỉnh có thể đến từ đỉnh u các đỉnh chưa hề đi qua. Ta có thể dùng hàm Dembac(u) để đếm từ đỉnh u và hàm Bacnhonhat(u) để lưu giá trị của bậc của đỉnh v nào đó có thể đến từ u và bậc của nó là nhỏ nhất. Dùng biến count để đếm bước đi của mã. Khi count=nxn nghĩa là ta đã được hành trình. Mảng b: array[1 nxn] để lưu số x với x là chỉ số x bước thì đến đỉnh b[i]=x,b[i]=0 nếu như ô đó chưa đi qua. Ta cũng dùng luôn mảng này để kiểm tra xem một đỉnh đã được đi qua hay chưa. Toàn bộ văn bản chương trình như sau: Program Ma_di_tuan; Const max =50; Var b:array[1 max*max] of integer; N,x,y,count:integer; Function kt(u,v:integer):boolean; Var x1,x2,y2,y1:integer; Begin x1:=(u-1)div n +1; If u mod n =0 then y1:=n Else y1:=u mod n; X2:=(v-1) div n+1; If v mod n =0 then y2:=n Else y2:=u mod n; Kt:= (abs (x1-x2)*abs(y1=y2)=2); End; Function Dembac(u:integer):integer; {dem so dinh co the den tu u ma chua di qua} Var tg,v:integer; Begin tg:=0; For v:=1 to n*n do {Duyet mo dinh} If (b[v]=0) and kt(u,v) then inc(tg); Dembac:=tg; End; Function Bacnhonhat(u:integer):integer; Var v,tg:integer Begin tg:=10; For v:=1 to n*n do If (b[v]=0) and kt(u,v) and (tg>Dembac(v)) then Tg:=dembac(v); Bacnhonhat:=tg; End; Procedure printResult; Var u:integer; Begin For u:=1 to n*n do If u mod n =0 then Writeln(b[u], ′ ′) Else write(b[u], ′ ′); Readln; Halt; End; Procedure Dat(u:integer); Var v:integer; Begin For v:=1 to n*n do If (b[v]=0)and kt(u,v) and (Dembac(v)=Bacnhonhat(u)) then Begin Inc(count);b[v]:=count; If count=n *n then PrintResult Else Dat(v); Dec(count); b[v]:=0; End; Begin Write(′kich thuoc ban co:′); readln(n); Write(′toa do o dang dung:′); readln(x,y); X:=(x-1)*n+y; B[x]:=1; count:=1; Dat(x); End. Nhận xét: Chương trình trên với 2≤n≤18 chạy với tốc độ <1 giây (trường hợp có cách đặt). Với n lớn hơn chương trình chạy khoảng>3 giây (n=30). Tuy nhiên trường hợp khó xử lý đó là nếu không có hành trình, do phải duyệt hết các trường hợp nên chạy không hơn chương trình duyệt bình thường, các bạn thử tìm cách giải xem? Nếu các bạn có thăc mắc xin liên hệ với tác giả qua mail: ngtrung882003@yahoo. . Thuật toán hiệu quả giải bài toán Mã đi tuầnNguyễn Văn TrungHẳn các bạn học lập trình pascal đã biết đến bài toán Mã đi tuần : Cho bàn. khi mất hết kiên nhẫn. Vì vậy mục đích của bài toán này là nêu ra một thuật giải hiệu quả hơn cho bài toán Mã đi tuần. Ta coi bàn cờ nxn như một đồ thị vô

Ngày đăng: 07/09/2012, 10:30

Từ khóa liên quan

Tài liệu cùng người dùng

Tài liệu liên quan