我正在尝试编写代码,使用UCS和A*算法解决汉诺塔问题,然后比较结果。因此,我首先要做的是将可能的移动表示为树,这样UCS和A*算法就可以轻松地遍历这棵树。
假设我们有3个堆栈和5个圆盘,那么初始状态将是:
# The Num of stacks is the number of elements in the list.# The Num of disks is the length of each element in the list.key = ["12345","00000","00000"]# A B C
我需要构建一个函数来预测可能的下一步移动,因此下一步可能是:
["12340","00005","00000"] or ["12340","00000","00005"]# 所以这些状态将被保存为:dic ={}x= repr(key)dic[x] = ["12340","00005","00000"]# 结果:# ["12345","00000","00000"] : ["12340","00005","00000"]
我尝试了这个简单的代码:
# there are bugs but I am still working on it for indx, block in enumerate(key): for i, char in enumerate(reversed(block)): if char != "0": for indx2, block2 in enumerate(key): if indx2 == indx: pass for ii, char2 in enumerate(reversed(block2)): if char2 == "0": temp=block[i] block[i]= block2[ii] block2[ii]=temp print(key)
有什么伪代码或想法可以帮助吗?
回答:
解决汉诺塔问题不需要构建状态图,因为有一个数学公式可以确定下一步的移动。
不过,如果你打算构建这个图,我建议将键简化为这种格式:12345||
。管道符号分隔堆栈。所以如果你将5移动到中间堆栈,它的键将是1234|5|
。然后如果你将4移动到最后一个堆栈:123|5|4
,依此类推。
在创建图的过程中,你可以切换到列表的列表形式,如[["1","2","3"], [], []]
,这样更容易操作。你使用字典的想法很好,但是从一个状态可能有几个有效的移动,所以你需要一个状态列表。
图中的节点通常使用Node
类实现,所以我建议使用以下代码:
class Node: def __init__(self, key): self.key = key self.children = []def create_tree(stacks, tree=None): if not tree: tree = {} key = "|".join(["".join(discs) for discs in stacks]) if key in tree: # this node was already created return tree[key] tree[key] = node = Node(key) for source in stacks: if source: disc = source[-1] for target in stacks: if not target or disc > target[-1]: # perform the move: target.append(source.pop()) # recursion node.children.append(create_tree(stacks, tree)) # undo the move source.append(target.pop()) return noderoot = create_tree([["1","2","3","4","5"], [], []])
运行此代码后,root
将是一个Node
实例,其children
属性中有两个节点。这些子节点中的每一个将有三个子节点,包括一个指向根的反向引用,表示逆向移动。
我将字典(称为tree
)隐藏在实现中。如果你觉得需要访问它,当然可以将其设为非局部变量,或作为参数传递。