演算法 馬走日

2021-08-31 23:33:30 字數 3273 閱讀 4135

題目描述:

在西洋棋中,馬的走法與中國象棋類似,即俗話說的「馬走日」,下圖所示即西洋棋中馬每一步能到達的格仔(箭頭所指為每步到達位置)。

現有一200 * 200大小的西洋棋棋盤,棋盤中僅有乙個馬,給定馬的當前位置和目標位置,求出馬最少需要多少跳才能從當前位置到達目標位置。

輸入格式:已有檔案txt格式

檔案裡每一行有四個以空格分隔的整數,分別表示馬當前位置及目標位置的橫、縱座標(xs,ys)和(xe,ye)。座標由0開始。

檔案輸入樣例:

1 1 2 1

1 5 5 1

輸入說明

第一行:馬的當前位置為(1,1),目標位置為(2,1)。

第二行:馬的當前位置為(1,5),目標位置為(5,1)。

輸出:檔案裡每一行第乙個數字為1個整數,即馬從當前位置跳到目標位置最少的跳數,然後以空格隔開,輸出對應的最短路徑座標,座標格式為(x, y),每個座標之間以空格隔開。所有路徑輸出後以回車換行。

輸出樣例:

3 (1, 1) (3, 2) (4, 0) (2, 1)

4 (1, 5) (2, 3) (4, 2) (6, 3) (5, 1)

第一行:馬需要跳3次才可以從(1,1)到(2,1),對應的路徑為(1, 1) (3, 2) (4, 0) (2, 1)。

第二行:馬需要跳4次才可以從(1,5)到(5,1),對應的路徑為(1, 5) (2, 3) (4, 2) (6, 3) (5, 1)。

解題:對於這類問題,可以用廣度優先bfs,或者深度優先演算法dfs,如果採用深度優先演算法dfs,則需要在所有的路徑中找最短的路徑。如果採用廣度優先bfs演算法,由於bfs的特點,保證是最短路徑,再加上乙個字典表來記錄每乙個位置的上一步(父親)

用佇列儲存將要訪問的座標,每訪問乙個座標,標記並把8個方向的座標也加入到佇列中,利用佇列的fifo特性依次訪問,直到隊列為空

思路如下:

1.輸入為起點位置start(xs,ys),終點為target(xe,ye)

2.建立乙個n*n(200*200)的陣列用來記錄每乙個座標是否被訪問過

3.從起點開始訪問它的八個相鄰方向,count+1,同時記錄這8個方向的前一步(父節點):

標記該座標為訪問過

如果是目標,則輸出count值和父節點字典中的路徑

如果不是,則遞迴查詢鄰居的鄰居

迴圈,直到找到目標

具體實現如下:

鄰接表:

visited = [[-1 for i in range(200)] for j in range(200)]  #初始值為-1
訪問的鄰居方向:dirs_list = [(-2, -1), (-2, 1), (-1, -2), (-1, 2), (1, -2), (1, 2), (2, -1), (2, 1)] # 8個方向

class solution:

def findpath(self,init_location,target_location):

visited = [[-1 for i in range(205)] for j in range(205)]

parent_dict = dict() # key值唯一,每個位置只對應乙個父節點

dirs_list = [(-2, -1), (-2, 1), (-1, -2), (-1, 2), (1, -2), (1, 2), (2, -1), (2, 1)] # 八個方向

qu = deque() #雙佇列

while qu:

cur_location = qu.popleft() #佇列頭出隊

if cur_location == target_location: #如果是目標,則列印路徑

self.path_print(target_location,parent_dict)

return

visited[cur_location[0]][cur_location[1]] = 1 #不是目標,標記為訪問過

for i in range(8): #得到8個方向的座標

next_row = cur_location[0] + dirs_list[i][0]

next_col = cur_location[1] + dirs_list[i][1]

if next_row < 0 or next_col < 0 or next_row >= 200 or next_col >= 200:

continue

if visited[next_row][next_col] < 0: #沒訪問過,則加入佇列

next_node = (next_row, next_col)

parent_dict[next_node] = cur_location #標記它的上一座標

visited[next_row][next_col] = 1 #訪問過一定要標記

if next_node == target_location: #如果是目標,則能不用再訪問前面的座標

self.path_print(target_location,parent_dict)

return

def path_print(self,target_location,parent_dict):

lst = [target_location]

cur_loc = target_location

shortest_num = 0

while parent_dict.get(cur_loc):

cur_loc = parent_dict[cur_loc]

shortest_num += 1

print(shortest_num,end=' ')

for i in range(len(lst)-1,-1,-1):

print(lst[i],end=' ')

#測試,輸入為:filename

with open(filename,'r',encoding='utf-8') as fp:

lines = fp.readlines()

for line in lines:

line = line.rstrip('\n')

line = line.split(' ')

init_loc = (int(line[0]),int(line[1]))

target_loc = (int(line[2]),int(line[3]))

print(init_loc,target_loc)

s = solution()

s.findpath(init_loc,target_loc)

馬走日棋盤演算法

問題描述 在給定大小的方格狀棋盤上,將棋子 馬 放在指定的起始位置 棋子 馬 的走子的規則為必須在棋盤上走 日 字 從棋子 馬 的起始位置開始,搜尋出一條可行的路徑,使得棋子 馬 能走遍棋盤上的所有落子點,而且每個落子點只能走一次 例如 棋盤大小為5 5 棋子馬放的起始落子點為 3 3 演算法需要搜...

百練 馬走日

總時間限制 記憶體限制 1000ms 1024kb 馬在中國象棋以日字形規則移動。請編寫一段程式,給定n m大小的棋盤,以及馬的初始位置 x,y 要求不能重複經過棋盤上的同乙個點,計算馬可以有多少途徑遍歷棋盤上的所有點。第一行為整數t t 10 表示測試資料組數。每一組測試資料報含一行,為四個整數,...

馬走日 最小步數

題目描述 一匹馬在乙個8 8的棋盤上走著,它的每一步恰好走成乙個日字,也就是在x y兩個方向上,如果在乙個方向走一步,另乙個方向就走兩步。假設棋盤的下標左下角是 1,1 右上角是 8,8 給你馬的最初位置p1 a1,b1 最終位置p2 a2,b2 請你程式設計求出馬從最初位置到最終位置所走的最少步數...