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
以上的代码还是有不少可优化的空间。