python数据结构学习笔记-2017-01-08-01-N皇后问题、迷宫问题和跳马问题的递归解决

        N皇后问题

        棋盘ADT

#-*-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

         递归解决N皇后问题,返回解的个数,修改一下,也可以返回全部解。

#-*-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

        以上的代码还是有不少可优化的空间。

         

    原文作者:迷宫问题
    原文地址: https://blog.csdn.net/baidu_21088863/article/details/54236713
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞