实验7 知识表示与推理
一、实验目的
(1)掌握知识和知识表示的基本概念,理解其在AI中的深刻含义与意义;
(2)熟悉AI中常用的知识表示方法的优缺点及其应用场景;
(3)掌握产生式系统知识表示的方法及其构成要素;
(4)掌握状态空间法的基本构成及其特点,能用其表示实际AI问题;
(5)深入理解图的深度、宽度搜索方法,并能应用于实际问题;
(6)根据自身情况,能选择合适的编程语言,解决实际AI问题。
二、实验内容
借助产生式系统和状态空间法,选择一种编程语言(最好为python或java),完成题目要求。
1、八数码难题
在3×3的棋盘上,摆有八个棋子,每个棋子上标有1至8的某一数字。棋盘中留有一个空格,空格可用0来表示。空格周围的棋子可以移到空格中。要求解的问题是:给出一种初始布局(初始状态)和目标布局,找到一种移动方法,实现从初始布局到目标布局的转变。
import heapq
计算了两个状态(state 和 goal)之间的曼哈顿距离
python
def manhattan_distance(state, goal):
distance = 0
for i in range(1, 9):
x1, y1 = divmod(state.index(i), 3)
x2, y2 = divmod(goal.index(i), 3)
distance += abs(x1 - x2) + abs(y1 - y2)
return distance
# 在 A* 算法 中的一个节点。代表了搜索空间中的一个状态
class Node:
def __init__(self, state, parent=None, move=0, depth=0):
self.state = state
self.parent = parent
self.move = move
self.depth = depth
self.cost = 0 # g(n) + h(n)
def __lt__(self, other):
return self.cost < other.cost
# A* 算法
# 结合实际成本(g(n))和估计成本(h(n))来选择最有希望的路径
# g(n) 是从起始节点到当前节点的移动次数(或称为深度),
# 而 h(n) 是当前状态与目标状态之间的曼哈顿距离
def a_star(initial, goal):
open_list = []
closed_set = set()
root = Node(initial)
heapq.heappush(open_list, (manhattan_distance(initial, goal), root))
while open_list:
_, current = heapq.heappop(open_list)
closed_set.add(tuple(current.state))
if current.state == goal:
path = []
while current:
path.append(current.state)
current = current.parent
return path[::-1]
zero_pos = current.state.index(0)
x, y = divmod(zero_pos, 3)
moves = [(-1, 0), (1, 0), (0, -1), (0, 1)]
for dx, dy in moves:
new_x, new_y = x + dx, y + dy
if 0 <= new_x < 3 and 0 <= new_y < 3:
new_state = current.state[:]
new_pos = new_x * 3 + new_y
new_state[zero_pos], new_state[new_pos] = new_state[new_pos], new_state[zero_pos]
if tuple(new_state) not in closed_set:
new_node = Node(new_state, current, move=current.move + 1, depth=current.depth + 1)
new_node.cost = new_node.depth + manhattan_distance(new_state, goal)
heapq.heappush(open_list, (new_node.cost, new_node))
return None
# 手动输入初始状态和目标状态
# initial_state = [int(input(f"请输入位置 {i+1} 的数字(0-8): ")) for i in range(9)]
initial_state = [1, 3, 2, 4, 7, 6, 0, 5, 8]
goal_state = [1, 2, 3, 4, 5, 6, 7, 8, 0]
solution = a_star(initial_state, goal_state)
def print_state(state):
"""
以3x3网格的形式打印状态
:param state: 包含九个数字的列表,代表拼图的一个状态
"""
for i in range(0, 9, 3):
print('\t'.join(map(str, state[i:i + 3])))
print() # 每打印完一个状态后添加一个空行
if solution:
for step in solution:
print_state(step)
else:
print("无解")
2、设有3个传教士和3个野人来到河边,打算乘一只船从右岸渡到左岸去。该船每一次只能装载2人。在任何时候,如果野人人数超过传教士人数,那么野人就会把传教士吃掉。请你设计一个方案怎样才能用这条船安全地把所有人都渡过河去?编程实现你的方案。
python
from collections import deque
def is_valid_state(left_missionaries, left_cannibals):
if left_missionaries < 0 or left_cannibals < 0:
return False
if (3 - left_missionaries) < 0 or (3 - left_cannibals) < 0:
return False
if (left_missionaries > 0 and left_cannibals > left_missionaries) or ((3 - left_missionaries) > 0 and (3 - left_cannibals) > (3 - left_missionaries)):
return False
return True
def next_states(state):
left_missionaries, left_cannibals, right_missionaries, right_cannibals, boat_position = state
next_states_list = []
if boat_position == 'left':
for i in range(3):
for j in range(3):
if i + j > 0 and i + j <= 2:
new_left_missionaries = left_missionaries - i
new_left_cannibals = left_cannibals - j
new_right_missionaries = right_missionaries + i
new_right_cannibals = right_cannibals + j
if is_valid_state(new_left_missionaries, new_left_cannibals):
next_states_list.append((new_left_missionaries, new_left_cannibals, new_right_missionaries, new_right_cannibals, 'right'))
else:
for i in range(3):
for j in range(3):
if i + j > 0 and i + j <= 2:
new_left_missionaries = left_missionaries + i
new_left_cannibals = left_cannibals + j
new_right_missionaries = right_missionaries - i
new_right_cannibals = right_cannibals - j
if is_valid_state(new_left_missionaries, new_left_cannibals):
next_states_list.append((new_left_missionaries, new_left_cannibals, new_right_missionaries, new_right_cannibals, 'left'))
return next_states_list
def bfs():
initial_state = (3, 3, 0, 0, 'left')
goal_state = (0, 0, 3, 3, 'right')
visited = set()
queue = deque([(initial_state, [])])
while queue:
state, path = queue.popleft()
if state == goal_state:
return path + [state]
if state not in visited:
visited.add(state)
for next_state in next_states(state):
queue.append((next_state, path + [state]))
return None
path = bfs()
if path is None:
print("未找到解决方案。")
else:
print("解决方案:")
for state in path:
left_missionaries, left_cannibals, right_missionaries, right_cannibals, boat_position = state
if boat_position == "left":
print(f"左岸有{left_missionaries}个传教士和{left_cannibals}个野人。右岸有{right_missionaries}个传教士和{right_cannibals}个野人。船在左岸。")
else:
print(f"左岸有{left_missionaries}个传教士和{left_cannibals}个野人。右岸有{right_missionaries}个传教士和{right_cannibals}个野人。船在右岸。")
三、实验报告
1、需求分析
2、数据结构、功能模块设计与说明
3、核心代码(不要将全部代码贴在报告上)与测试结果说明
4、实验存在的问题与体会
5、实验指导与源代码、程序运行环境与运行说明等打包,以班级+学号+姓名命名,统一发给课代表或学委。