python資料結構學習筆記-2017-01-08-01-N皇后問題、迷宮問題和跳馬問題的遞迴解決
阿新 • • 發佈:2019-01-29
N皇后問題
棋盤ADT
遞迴解決N皇后問題,返回解的個數,修改一下,也可以返回全部解。#-*-coding: utf-8-*- # 二維陣列實現棋盤ADT from myarray2d import Array2D class Board(object): def __init__(self, n): self._board = Array2D(n, n) self._size = n def size(self): return self._size def numQueens(self): count = 0 for row in range(self.size()): for col in range(self.size()): if self._board[row, col] == 1: count += 1 return count def unguarded(self, row, col): if self._board[row, col]: return False else: directions = [(0, 1), (0, -1), (-1, 0), (1, 0), (1, 1), (-1, -1), (1, -1), (-1, 1)] for direction in directions: r = row c = col while 0 <= r < self.size() and 0 <= c < self.size(): if self._board[r, c] == 1: return False else: r += direction[0] c += direction[1] return True def placeQueen(self, row, col): assert self.unguarded(row, col), "Cannot place a queen here." self._board[row, col] = 1 def removeQueen(self, row, col): self._board[row, col] = 0 def reset(self): for row in range(self.size()): for col in range(self.size()): if self._board[row, col] == 1: self.removeQueen(row, col) def draw(self): for row in range(self.size()): string = '' for col in range(self.size()): if self._board[row, col]: string += '@ ' else: string += '. ' print string
#-*-coding: utf-8-*- # N皇后問題 from board import Board # 該函式只是驗證N皇后問題解的存在性 def solveNQueens(board, col): if board.numQueens() == board.size(): # 確定所有皇后是否都放置好了 return True else: # 在這一列找出正確的位置放置皇后 for row in range(board.size()): if board.unguarded(row, col): board.placeQueen(row, col) if solveNQueens(board, col+1): return True else: board.removeQueen(row, col) return False # 沒有找到正確位置,則會回溯到上一列的皇后放置上來。 # 返回的count是solveNQueensCounts(board, col),其中的col是最開始的0,如果使用區域性變數有些麻煩,用全域性變數就相對好處理一些。 count = 0 def solveNQueensCounts(board, col): for row in range(board.size()): if board.unguarded(row, col): board.placeQueen(row, col) if board.numQueens() == board.size(): # 確定找到一個解了 # board.draw() global count count += 1 board.removeQueen(row, col) # 確定一個解後,需要將最後一個皇后拿掉 else: solveNQueensCounts(board, col+1) board.removeQueen(row, col) # 無論在col+1列放置皇后是否成功,都必須將原來在col列放置的皇后拿掉,再嘗試在該列的下一個位置。因為col+1列沒有放置成功,顯然放置在col列的皇后要拿掉。如果在col+1列放置成功,並找到了在前面col列的皇后都不動的情況下的所有解之後,要尋找接下來的解,顯然也要移動col列上的皇后。 return count if __name__ == "__main__": n = int(raw_input("Please enter the size of board: ")) board = Board(n) # solveNQueens(board, 0) # board.draw() print solveNQueensCounts(board, 0)
迷宮問題
迷宮ADT
遞迴解決迷宮問題#-*-coding: utf-8-*- # 迷宮ADT from myarray2d import Array2D # from lliststack import Stack class Maze(object): MAZE_WALL = "*" # 牆 PATH_TOKEN = "x" # 表示走過的路徑 TRIED_TOKEN = "o" # 死路 PathFound = False def __init__(self, numRows, numCols): self._mazeCells = Array2D(numRows, numCols) self._startCell = None self._exitCell = None def numRows(self): return self._mazeCells.numRows() def numCols(self): return self._mazeCells.numCols() def setWall(self, row, col): assert 0 <= row < self.numRows() and 0 <= col < self.numCols(), "Cell index out of range." self._mazeCells[row, col] = Maze.MAZE_WALL def setStart(self, row, col): assert 0 <= row < self.numRows() and 0 <= col < self.numCols(), "Cell index out of range." self._startCell = _CellPosition(row, col) def setExit(self, row, col): assert 0 <= row < self.numRows() and 0 <= col < self.numCols(), "Cell index out of range." self._exitCell = _CellPosition(row, col) def getStart(self): return self._startCell.row, self._startCell.col def getExit(self): return self._exitCell.row, self._exitCell.col def findPath(self, row, col): self._markPath(row, col) # 首先對當前位置進行標記'x' # print row, col if self._exitFound(row, col): # 確認當前位置是否是終點,是就修改類屬性Maze.PathFound Maze.PathFound = True else: chioce = 0 # 先確定在這一位置上是否有路可走 dirctions = [(0, 1), (1, 0), (0, -1), (-1, 0)] for dirction in dirctions: r = row + dirction[0] c = col + dirction[1] if self._validMove(r, c): chioce += 1 if chioce == 0: # 若無路可走則標記'o' self._markTried(row, col) else: for dirction in dirctions: r = row + dirction[0] c = col + dirction[1] if Maze.PathFound: # 一旦確認已到達終點,停止遞迴呼叫,進入遞迴返回 break if self._validMove(r, c): self.findPath(r, c) if Maze.PathFound: # 確認是否找到到達終點的路徑 return True else: return False # 刪除所有標記,即"x"和"o"。 def reset(self): for row in range(self.numRows()): for col in range(self.numCols()): if self._mazeCells[row, col] in 'ox': self._mazeCells[row, col] = None def draw(self): for row in range(self.numRows()): str = '' for col in range(self.numCols()): if self._mazeCells[row, col] != None: str += self._mazeCells[row, col] else: str += '.' print str # 是否能移動到該位置 def _validMove(self, row, col): return 0 <= row < self.numRows() and 0 <= col < self.numCols() and self._mazeCells[row, col] is None # 判斷當前點是否為終點 def _exitFound(self, row, col): return row == self._exitCell.row and col == self._exitCell.col # 將該位置設定為死路 def _markTried(self, row, col): self._mazeCells[row, col] = Maze.TRIED_TOKEN # 標記走過的路 def _markPath(self, row, col): self._mazeCells[row, col] = Maze.PATH_TOKEN # 儲存類 class _CellPosition(object): def __init__(self, row, col): self.row = row self.col = col
#-*-coding: utf-8-*-
# 從檔案中建立迷宮,並解決迷宮
from recmaze import Maze
# 建立迷宮
def buildMaze(filename):
with open(filename, 'r') as infile:
nrows, ncols = readValuePair(infile) # 迷宮大小
maze = Maze(nrows, ncols) # 建立迷宮,並初始化
row, col = readValuePair(infile)
maze.setStart(row, col) # 根據給定座標設定起始點
row, col = readValuePair(infile)
maze.setExit(row, col)
for row in range(nrows):
line = infile.readline()
for col in range(len(line)):
if line[col] == "*":
maze.setWall(row, col)
infile.close()
return maze
# 輔助方法,從給定檔案中讀取整數對值
def readValuePair(infile):
line = infile.readline()
(valA, valB) = tuple(line.split())
return int(valA), int(valB)
def main():
maze = buildMaze("mazefile.txt")
if maze.findPath(maze.getStart()[0], maze.getStart()[1]):
print "Path found ..."
maze.draw()
else:
print "Path not found ..."
if __name__ == "__main__":
main()
跳馬問題
棋盤ADT
#-*-coding: utf-8-*-
# 跳馬問題國際象棋棋盤ADT
from myarray2d import Array2D
class ChessBoard(object):
PATH_FOUND = False
COUNT = 0
def __init__(self, n):
self._board = Array2D(n, n)
self._size = n
self._start = None
def size(self):
return self._size
def setStart(self, row, col):
assert 0 <= row < self._size and 0 <= col < self._size, "Out of range."
self._start = _CellPosition(row, col)
def _validMove(self, row, col):
return 0 <= row < self._size and 0 <= col < self._size and self._board[row, col] == None
# 尋找路徑
def findPath(self, row, col):
# print row, col
self._board[row, col] = ChessBoard.COUNT
ChessBoard.COUNT += 1
if ChessBoard.COUNT == self._size ** 2: # 通過步數來判斷棋盤是否已經遍歷完
ChessBoard.PATH_FOUND = True
else:
choice = 0
directions = [(1, 2), (2, 1), (-1, -2), (-2, -1), (1, -2), (-1, 2), (-2, 1), (2, -1)] # 方向
for direction in directions:
r = row + direction[0]
c = col + direction[1]
if self._validMove(r, c):
choice += 1
if choice:
for dirction in directions:
r = row + dirction[0]
c = col + dirction[1]
if self._validMove(r, c):
self.findPath(r, c)
else:
self._board[row, col] = None
ChessBoard.COUNT -= 1
return False
if ChessBoard.PATH_FOUND:
print row, col
return True
else:
self._board[row, col] = None # 注意如果一個位置有路可走,但經試驗都是死路的話,必須將這個位置復原!
class _CellPosition(object):
def __init__(self, row, col):
self.row = row
self.col = col
遞迴解決跳馬問題
#-*-coding: utf-8-*-
from recchessboard import ChessBoard
def knightTour(board, row, col):
if isinstance(board, ChessBoard):
board.setStart(row, col)
board.findPath(row, col)
if __name__ == "__main__":
board = ChessBoard(5)
row = int(raw_input("Please enter a positive integer less than 5: "))
col = int(raw_input("Please enter a positive integer less than 5: "))
knightTour(board, row, col)
print board.COUNT
以上的程式碼還是有不少可優化的空間。