1. 问题: 四个同心园盘的扇区数字如图所示,每个圆盘可以单独转动,如何设计搜索算法转动 圆盘使得 8 个扇区径向数字之和均为 12.
2.节点的初态以及终态:
![]() | ![]() | ||
3. 搜索策略的设计:
设计一个A 算法,利用一个评价函数来引导搜索的进行。
f(n) = g(n) + h(n)
f(n):评价函数,对当前节点的状态进行评估。依据此评估的结果对决定搜索的优先次序。
g(n): 表示搜索的深度。
h(n): 表示为扇区和不为12的扇区的个数。由于对于任意一种状态来说,转盘只需要转动三次就可以达到要求,而当前的h(n) 显然大于h*(n) 因此,不满足A*算法的要求,故此算法为A算法。
4. 代码实现。
import numpy as np
class Node:
def __init__(self, status, parent, gValue, hValue, id, chage): # 当一个节点被创建的时候,其父节点 g , h 的 值都应该知道
self.status = status
self.parent = parent
self.gValue = gValue
self.hValue = hValue
self.children = [] # 用于存储基于当前节点的孩子节点
self.fValue = gValue + hValue
self.id = id
self.chage = chage
def __lt__(self, other): # 可以根据此函数对该类型的节点进行排序
return self.fValue < other.fValue
def computer_hValue(data): # 获取当前状态的hValue
rowSum = np.sum(data, axis=1)
return sum(rowSum != 12)
def isFinish(data):
rowSum = np.sum(data, axis=1)
return sum(rowSum != 12)
def exchange(data, start, end): # 列表数据的交换 在转动的循环过程中使用
while start < end:
data[start], data[end] = data[end], data[start]
start += 1
end -= 1
def getNewState(data, i, j): # 应用规则生成新状态
exchange(data[:, i], 0, len(data[:, i]) - j - 1) # 前半部分进行倒置
exchange(data[:, i], len(data[:, i]) - j, len(data) - 1) # 后半部分进行倒置
exchange(data[:, i], 0, len(data[:, i]) - 1) # 所有的元素全部进行倒置
def isIn(node, Nodes):
for n in Nodes:
if (n.status == node.status).all():
return n
return None
def huisu(result):
print("开始回溯")
while result:
print(result.status)
result = result.parent
def getResult(openList, closeList):
count = 0
id = 0
while openList: # 当open 表不为空的时候
node = openList.pop(0) # 从open 表中取出第一个节点
print("我的id",node.id)
if node.parent:
print("父节点的id",node.parent.id)
if node.chage:
print(node.chage)
print("当前选中的节点", " g:", node.gValue, "h: ", node.hValue)
print("当前节点的状态", node.status)
if isFinish(node.status) == 0:
print("结束", "g: ", node.gValue, "f", node.hValue)
print(node.status)
print("一共扩展了 ", count, "次")
return newNode
closeList.append(node) # 将其加入到close表中
count+=1
for i in range(4): # 一共四个圆盘 转哪个都可以
for j in range(1, 8): # 每一个圆盘8个数 转动的幅度一共可以产生其中不同的结果 j 表示转动的幅度
id += 1
newNodeStatus = node.status.copy() # 新的节点的状态是以上上一个节点为基础产生的
getNewState(newNodeStatus, i, j) # 获取新节点的状态
hValue = computer_hValue(newNodeStatus) # 计算新节点的fValue
change =f'转盘{i+1}顺时针旋转了{j*45}度'
newNode = Node(newNodeStatus, node, node.gValue + 1, hValue, id, change) # 利用新状态创建新节点 新创建的结点的g值为其父节点g值+1
nodeOpen = isIn(newNode, openList) # 是不是在open表中
nodeClose = isIn(newNode, closeList) # 是不是在close 表中
if nodeOpen is not None: # 表示新生成的节点在open表中
if nodeOpen.fValue > newNode.fValue: # 如果后面的节点最优的话 调整节点
nodeOpen.gValue = newNode.gValue
nodeOpen.fValue = newNode.fValue
nodeOpen.parent = newNode.parent
if nodeClose is not None: # 表示节点在close表中
if nodeClose.fValue > newNode.fValue: # 判断节点是否需要重新加入到open表中
closeList.remove(nodeClose)
openList.append(newNode)
if not isIn(newNode, openList) and not isIn(newNode, closeList): # 表示新节点既不在open表也不在close表
openList.append(newNode)
openList.sort()
if __name__ == '__main__':
data = np.array([[5, 5, 2, 3], [3, 1, 2, 2], [2, 3, 1, 2], [3, 2, 3, 5], [4, 1, 4, 1], [1, 3, 5, 5], [3, 4, 3, 3],
[4, 2, 5, 4]]) # 数据集 表示轮盘 四列表示一个扇区的四个数字, 8行表示8个扇区
openList = [] # +表示open表
closeList = [] # 表示close表
start = Node(data, None, 0, computer_hValue(data),0,None)
openList.append(start) # 讲初始结点加入open表
result = getResult(openList, closeList)
huisu(result)