人工智能(第三版)—【第二章】编程题

1.编写程序来解决 15 拼图的实例,首先检查目标状态是否可达。你的程序应该利用下列搜索算法。

(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表示空格。你可以根据你的具体需求修改初始状态和目标状态。
以上是一个简单的实现,但是对于较复杂的拼图问题,可能需要更高效的算法来提高搜索效率。


3.编写程序,使用回溯法来解决 8 皇后问题,然后回答以下问题。

(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皇后问题时,我们按行逐个放置皇后,并使用集合来记录已经占用的列、对角线和反对角线,以确保每个皇后不会互相攻击。


4.编写程序,采用习题 5 中建议的生成器解决 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

生成器解决方法可以逐个生成解,而不是一次性生成所有解,这对于大规模问题或需要逐步处理解的情况很有用。


5.在国际象棋中,马有以下 8 种不同的走子方式:

(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。
最后,将生成的棋盘打印出来。

请注意,由于马踏棋盘问题的解并不唯一,程序每次运行可能会得到不同的结果。

你可能感兴趣的:(python,人工智能,深度学习)