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

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

3 6,5K 99
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

Tiêu đề Thuật toán hiệu quả giải bài toán mã đi tuần
Tác giả Nguyễn Văn Trung
Trường học Trường Đại Học
Chuyên ngành Lập trình Pascal
Thể loại Bài luận
Năm xuất bản 2023
Thành phố Hà Nội
Định dạng
Số trang 3
Dung lượng 32 KB

Các công cụ chuyển đổi và chỉnh sửa cho tài liệu này

Nội dung

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

Trang 1

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

Nguyễn Văn Trung

Hẳ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 Mã 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 mã 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 Mã 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

Mã đ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 mã đ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 mã 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 mà chưa hề đi qua)

Như vậy số bậc của đỉnh u là số đỉnh có thể đến từ đỉnh u mà 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

Trang 2

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ì mã đế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

Trang 3

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

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

🧩 Sản phẩm bạn có thể quan tâm

w