題目描述:解題:對於這類問題,可以用廣度優先bfs,或者深度優先演算法dfs,如果採用深度優先演算法dfs,則需要在所有的路徑中找最短的路徑。如果採用廣度優先bfs演算法,由於bfs的特點,保證是最短路徑,再加上乙個字典表來記錄每乙個位置的上一步(父親)在西洋棋中,馬的走法與中國象棋類似,即俗話說的「馬走日」,下圖所示即西洋棋中馬每一步能到達的格仔(箭頭所指為每步到達位置)。
現有一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)。
用佇列儲存將要訪問的座標,每訪問乙個座標,標記並把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 請你程式設計求出馬從最初位置到最終位置所走的最少步數...