# 目标序列end = [1,2,3,8,0,4,7,6,5] # end = 1 2 3 # 8 0 4 # 7 6 5 import sys class Statusobj: def __init__(self): # 状态序列 self.array = [] # 该状态下的深度 self.deep = 0 # 该状态的f(n) = g(n) + h(n)评估函数值 self.Fn = 0 # 该状态由上一个状态经何种操作得到,避免出现死循环 # 1:up 2:down 3:left 4:right self.preoperate = 0 self.Father = Statusobj # 判断八数码问题是否有解,在于若两个状态的逆序奇偶性 相同,则可相互到达,否则不可相互到达 def getreversenum(array): # 获取当前状态的逆序数和 count = 0 for i in range(len(array)): for j in range(i+1, len(array)): if array[j] < array[i]: count += 1 return count def countnotinplace(array, end): # 统计当前状态和目标状态相比较的不在位将牌数 count = 0 for i in range(len(array)): if array[i] != end[i] and array[i] != 0: count += 1 return count def selectoperate(i, preoperate): # 通过当前状态下的序列下标和上一次操作符得到可选择的操作 selected = [] if 3 <= i <= 8 and preoperate != 2: selected.append(1) if 0 <= i <= 5 and preoperate != 1: selected.append(2) if i in [1, 2, 4, 5, 7, 8]: if preoperate != 4: selected.append(3) if i in [0, 1, 3, 4, 6, 7]: if preoperate != 3: selected.append(4) return selected def op(i, x): # 通过操作符得到新下标 if i == 1: # up return x-3 if i == 2: # down return x+3 if i == 3: # left return x-1 if i == 4: # right return x+1 def newarray(operate, array): # 通过操作符拓展的新节点 subscript = array.index(0) newindex = op(operate, subscript) temp = array[subscript] array[subscript] = array[newindex] array[newindex] = temp return array def printarray(array): print(f"{array[:3]}\n{array[3:6]}\n{array[6:]}\n", end='') def main(): openlist = [] # open表,保存待扩展实例对象 closelist = [] # close表 endarray = [1, 2, 3, 8, 0, 4, 7, 6, 5] initobj = Statusobj() initobj.array = list(map(int, input("请输入原始状态的八数码序列:").split())) initobj.deep = 0 # 初始化执行深度 initobj.Fn = initobj.deep + countnotinplace(initobj.array, endarray) openlist.append(initobj) array_reverse = getreversenum(initobj.array) - initobj.array.index(0) end_reverse = getreversenum(endarray) - endarray.index(0) if array_reverse % 2 == end_reverse % 2: while True: if openlist[0].array == endarray: # 达到目标状态 end_list = [] end_list.append(openlist[0]) deep = openlist[0].deep closelist.append(openlist[0]) del openlist[0] father = closelist[-1].Father while father.deep >= 1: end_list.append(father) father = father.Father end_list.append(initobj) print("目标状态:") printarray(endarray) print("【变换成功,共需要" + str(deep) + "次变换】") d = 0 for it in reversed(end_list): print("当前深度为:{}".format(d)) d += 1 print("操作序号为:{}".format(it.preoperate)) printarray(it.array) sys.exit() else: zero_index = openlist[0].array.index(0) temp_list = [] operation = selectoperate(zero_index, openlist[0].preoperate) for ope in operation: copy_array = openlist[0].array.copy() # .copy()复制序列,必不可少 new_array = newarray(ope, copy_array) new_obj = Statusobj() new_obj.array = new_array # 序列 new_obj.deep = openlist[0].deep + 1 # 深度 new_obj.preoperate = ope # 上一操作符 new_obj.Father = openlist[0] # 父亲节点 new_obj.Fn = new_obj.deep + countnotinplace(new_array, endarray) # 评估函数 temp_list.append(new_obj) closelist.append(openlist[0]) del openlist[0] for item in temp_list: openlist.append(item) openlist.sort(key=lambda x: x.Fn) else: print("此情况下无解!") main() # 2 8 3 1 6 4 7 0 5