(a)深度优先搜索。
(b)广度优先搜索。
(c)迭代加深的深度优先搜索。
下面是使用Python编写的解决15拼图问题的程序,包括深度优先搜索、广度优先搜索和迭代加深的深度优先搜索算法。
class PuzzleNode:
def __init__(self, state, parent=None, action=None):
self.state = state
self.parent = parent
self.action = action
def get_path(self):
path = []
node = self
while node.parent:
path.append(node.action)
node = node.parent
path.reverse()
return path
class PuzzleSolver:
def __init__(self, initial_state, goal_state):
self.initial_state = initial_state
self.goal_state = goal_state
def is_goal_state(self, state):
return state == self.goal_state
def get_possible_actions(self, state):
actions = []
blank_index = state.index(0)
if blank_index % 4 > 0:
actions.append('left')
if blank_index % 4 < 3:
actions.append('right')
if blank_index // 4 > 0:
actions.append('up')
if blank_index // 4 < 3:
actions.append('down')
return actions
def get_new_state(self, state, action):
new_state = state[:]
blank_index = new_state.index(0)
if action == 'left':
new_state[blank_index], new_state[blank_index - 1] = new_state[blank_index - 1], new_state[blank_index]
elif action == 'right':
new_state[blank_index], new_state[blank_index + 1] = new_state[blank_index + 1], new_state[blank_index]
elif action == 'up':
new_state[blank_index], new_state[blank_index - 4] = new_state[blank_index - 4], new_state[blank_index]
elif action == 'down':
new_state[blank_index], new_state[blank_index + 4] = new_state[blank_index + 4], new_state[blank_index]
return new_state
def depth_first_search(self):
stack = [PuzzleNode(self.initial_state)]
visited = set()
while stack:
node = stack.pop()
state = node.state
if self.is_goal_state(state):
return node.get_path()
visited.add(tuple(state))
actions = self.get_possible_actions(state)
for action in actions:
new_state = self.get_new_state(state, action)
if tuple(new_state) not in visited:
stack.append(PuzzleNode(new_state, node, action))
return None
def breadth_first_search(self):
queue = [PuzzleNode(self.initial_state)]
visited = set()
while queue:
node = queue.pop(0)
state = node.state
if self.is_goal_state(state):
return node.get_path()
visited.add(tuple(state))
actions = self.get_possible_actions(state)
for action in actions:
new_state = self.get_new_state(state, action)
if tuple(new_state) not in visited:
queue.append(PuzzleNode(new_state, node, action))
return None
def iterative_deepening_search(self):
depth_limit = 0
while True:
result = self.depth_limited_search(depth_limit)
if result is not None:
return result
depth_limit += 1
def depth_limited_search(self, depth_limit):
stack = [PuzzleNode(self.initial_state)]
visited = set()
while stack:
node = stack.pop()
state = node.state
if self.is_goal_state(state):
return node.get_path()
if len(node.get_path()) < depth_limit:
visited.add(tuple(state))
actions = self.get_possible_actions(state)
for action in actions:
new_state = self.get_new_state(state, action)
if tuple(new_state) not in visited:
stack.append(PuzzleNode(new_state, node, action))
return None
# 示例使用
initial_state = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 0, 15]
goal_state = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 0]
solver = PuzzleSolver(initial_state, goal_state)
# 深度优先搜索
dfs_path = solver.depth_first_search()
print("深度优先搜索路径:", dfs_path)
# 广度优先搜索
bfs_path = solver.breadth_first_search()
print("广度优先搜索路径:", bfs_path)
# 迭代加深的深度优先搜索
ids_path = solver.iterative_deepening_search()
print("迭代加深的深度优先搜索路径:", ids_path)
请注意,这个程序假设拼图是一个4x4的方格,使用数字1到15表示拼图块,0表示空格。你可以根据你的具体需求修改初始状态和目标状态。
以上是一个简单的实现,但是对于较复杂的拼图问题,可能需要更高效的算法来提高搜索效率。
(a)有多少个解?
(b)这些解中有多少个是有区别的?(可通过阅读第 4 章的习题 5 来获得提示)
(c)使用哪种生成器?
以下是使用回溯法解决8皇后问题的Python代码:
def solve_n_queens(n):
def backtrack(row, cols, diagonals, anti_diagonals):
nonlocal count
if row == n:
count += 1
return
for col in range(n):
curr_diagonal = row - col
curr_anti_diagonal = row + col
if col in cols or curr_diagonal in diagonals or curr_anti_diagonal in anti_diagonals:
continue
cols.add(col)
diagonals.add(curr_diagonal)
anti_diagonals.add(curr_anti_diagonal)
backtrack(row + 1, cols, diagonals, anti_diagonals)
cols.remove(col)
diagonals.remove(curr_diagonal)
anti_diagonals.remove(curr_anti_diagonal)
count = 0
cols = set()
diagonals = set()
anti_diagonals = set()
backtrack(0, cols, diagonals, anti_diagonals)
return count
n = 8
total_solutions = solve_n_queens(n)
print(f"Total solutions: {total_solutions}")
(a) 8皇后问题共有92个解。
(b) 这些解中有12个不同的解。这是因为对称性导致部分解是重复的,可以通过旋转和镜像操作得到其他解。
© 该程序使用了回溯法来生成解。回溯法是一种递归的搜索算法,通过尝试所有可能的选择并进行回溯来找到问题的解。在解决8皇后问题时,我们按行逐个放置皇后,并使用集合来记录已经占用的列、对角线和反对角线,以确保每个皇后不会互相攻击。
以下是使用生成器解决8皇后问题的Python代码:
def solve_n_queens(n):
def is_safe(board, row, col):
# 检查列是否安全
for i in range(row):
if board[i] == col:
return False
# 检查左上方对角线是否安全
i, j = row - 1, col - 1
while i >= 0 and j >= 0:
if board[i] == j:
return False
i -= 1
j -= 1
# 检查右上方对角线是否安全
i, j = row - 1, col + 1
while i >= 0 and j < n:
if board[i] == j:
return False
i -= 1
j += 1
return True
def place_queens(board, row):
if row == n:
yield board
else:
for col in range(n):
if is_safe(board, row, col):
board[row] = col
yield from place_queens(board, row + 1)
board = [-1] * n
yield from place_queens(board, 0)
n = 8
solutions = list(solve_n_queens(n))
total_solutions = len(solutions)
print(f"Total solutions: {total_solutions}")
该程序使用了一个生成器函数solve_n_queens
来生成8皇后问题的解。在内部定义了两个辅助函数,is_safe
用于检查某个位置是否安全,place_queens
用于递归地放置皇后。
生成器函数solve_n_queens
首先创建一个长度为n
的列表board
,用于表示棋盘上每一行的皇后位置。然后通过place_queens
生成器递归地放置皇后,每次放置一个皇后并检查是否安全。当放置完所有皇后后,生成器会返回一个完整的解。
最后,将生成器的结果转换为列表solutions
,并计算解的总数total_solutions
。
生成器解决方法可以逐个生成解,而不是一次性生成所有解,这对于大规模问题或需要逐步处理解的情况很有用。
(1)从上一个方格,到右两个方格;
(2)从上一个方格,到左两个方格;
(3)从上两个方格,到右一个方格;
(4)从上两个方格,到左一个方格;
(5)从下一个方格,到右二个方格;
(6)从下一个方格,到左两个方格;
(7)从下两个方格,到右一个方格;
(8)从下两个方格,到左一个方格。
所谓 n×n 棋盘上的马踏棋盘问题(a knight’s tour,又称马周游、骑士漫游或骑士之旅问题),是指马从任何棋格出发,遍历剩下的 n2−1 个棋格,并且每个棋格只访问一次。显然整个过程是n2−1 步走子的序列。
编写程序,实现 n 等于 3~5 时的马踏棋盘问题。采用随机数生成器随机选择起始棋格并报
告程序的运行结果
以下是使用随机数生成器解决马踏棋盘问题的Python代码,其中n取值范围为3至5:
import random
def knight_tour(n):
def is_valid_move(x, y):
return 0 <= x < n and 0 <= y < n and board[x][y] == -1
def get_valid_moves(x, y):
moves = []
for dx, dy in knight_moves:
new_x = x + dx
new_y = y + dy
if is_valid_move(new_x, new_y):
moves.append((new_x, new_y))
return moves
def solve(board, x, y, move_count):
board[x][y] = move_count
if move_count == n * n:
return True
valid_moves = get_valid_moves(x, y)
random.shuffle(valid_moves)
for move in valid_moves:
new_x, new_y = move
if solve(board, new_x, new_y, move_count + 1):
return True
board[x][y] = -1
return False
knight_moves = [(-1, -2), (-2, -1), (-2, 1), (-1, 2),
(1, -2), (2, -1), (2, 1), (1, 2)]
while True:
board = [[-1] * n for _ in range(n)]
start_x = random.randint(0, n - 1)
start_y = random.randint(0, n - 1)
if solve(board, start_x, start_y, 1):
return board
n_values = [3, 4, 5]
for n in n_values:
print(f"n = {n}")
board = knight_tour(n)
for row in board:
print(row)
print()
该程序使用了一个递归函数solve
来解决马踏棋盘问题。在内部定义了两个辅助函数,is_valid_move
用于检查某个位置是否合法,get_valid_moves
用于获取某个位置的合法移动。
生成器函数knight_tour
首先创建一个空的n×n的棋盘,然后随机选择一个起始位置。接下来通过递归调用solve
函数来尝试解决问题。在solve
函数中,如果达到了要求的步数,则返回True,表示找到了解。否则,获取当前位置的合法移动,并随机打乱顺序,然后依次尝试每个合法移动。如果找到了解,则返回True,否则将当前位置标记为未访问,并返回False。
最后,将生成的棋盘打印出来。
请注意,由于马踏棋盘问题的解并不唯一,程序每次运行可能会得到不同的结果。