diff --git a/A算法-八数码问题.py b/A算法-八数码问题.py new file mode 100644 index 0000000..3625d28 --- /dev/null +++ b/A算法-八数码问题.py @@ -0,0 +1,137 @@ +# 目标序列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 \ No newline at end of file