2020-09-19

95 篇文章 2 订阅

八数码问题(再续)

参见八数码问题(续)
前面的程序还是存在问题。
其一,如果初始状态一步变化到目标状态,是不能获得最短路径的。
其二,内存开销比较多。
其三,表达不够精炼。
其四,对搜索层次没有规定,可能导致程序无法终止,或内存开销过大,异常退出。
有鉴于此,对程序再次进行修正。

# start = [7, 2, 3, 1, 6, 4, 8, 0, 5]
# end = [1, 2, 3, 8, 0, 4, 7, 6, 5]
start = [7, 2, 3, 1, 6, 4, 8, 0, 5]
end = [8, 1, 3, 5, 0, 4, 6, 7, 2]
# start = [7, 2, 3, 1, 6, 4, 8, 0, 5]
# end = [7, 2, 3, 1, 6, 4, 0, 8, 5]
# 记录空格(0)从一个状态(位置)变化到下一个状态(位置)信息
base = [[0, [1, 3]], [1, [0, 2, 4]], [2, [1, 5]], [3, [0, 4, 6]], [4, [1, 3, 5, 7]],
        [5, [2, 4, 8]], [6, [3, 7]], [7, [4, 6, 8]], [8, [5, 7]]]
sum_list, sum_list1 = [], []  # 存放链表数据
print("start", start)
print("end", end)


class Lists:  # 建立一个链表类,按层次保存状态列表
    def __init__(self, layer, father):
        self.layer = layer
        self.sun = moving(father)
        self.father = father


def moving(state):  # 统计从一个状态(father)变化到下一个状态(sun)的所有列表
    sun = []
    zero_ind = state.index(0)
    for b in base[zero_ind][1]:
        te = copy.deepcopy(state)
        te[b], te[zero_ind] = 0, te[b]
        sun.append(te)
    return sun


def solution(state):  # 判断是否有解
    ct = 0
    for k in range(9):
        if k != 0:
            for j in range(k):
                if state[j] != 0 and state[k] > state[j]:
                    ct += 1
    return ct


def search(summary, tier, state):  # 把某个层级所有状态列表汇总到一个列表
    for f in state:
        lis = Lists(tier, f)       # 实例化链表类
        for a in summary:          # 去重,关键环节
            if a.layer == tier - 1 and a.father in lis.sun:
                lis.sun.remove(a.father)
        summary.append(lis)
    ss = []
    for i in summary:
        if i.layer == tier:
            for ii in i.sun:
                ss.append(ii)
    return ss


def root(direction, layer, group):  # 搜根
    global middle, count
    temp, m = [], middle
    for i1 in range(layer, 0, -1):
        for g in group:
            if g.layer == i1 and (m in g.sun):
                temp.append(g.father)
                m = g.father
    if direction == 1:  # 正方向搜索时,完成后逆序输出
        temp.reverse()
        temp.append(middle)
    for t in temp:
        print(t)
    count += len(temp)


if __name__ == '__main__':
    import time
    import copy

    t0 = time.time()
    c1, c2 = solution(start), solution(end)
    if (c1 - c2) % 2 != 0:
        print("无解!")
        exit()
    if end in moving(start):
        print("成功!,共搜索1层。")
    s, e = [start], [end]
    c, count, middle = 1, 0, 0
    while True:
        list_order = search(sum_list, c, s)     # 从开始状态向目标状态搜索
        list_reverse = search(sum_list1, c, e)  # 从目标状态向开始状态搜索
        for r in sum_list:
            for r1 in sum_list1:
                if r.father == r1.father:
                    middle = r1.father          # 搜到共同的中间结果
                    root(1, c, sum_list)
                    root(0, c, sum_list1)
                    print("成功!共搜索{}层。".format(count - 1))
                    print("耗时{}s。".format(time.time() - t0))
                    exit()
        c += 1
        if c > 15:
            print("搜索层次超过设定值,失败!")
            exit()
        s, e = list_order, list_reverse
D:\Python\Python38\python.exe D:/Python/study/20200908/test10.py
start [7, 2, 3, 1, 6, 4, 8, 0, 5]
end [8, 1, 3, 5, 0, 4, 6, 7, 2]
[7, 2, 3, 1, 6, 4, 8, 0, 5]
[7, 2, 3, 1, 0, 4, 8, 6, 5]
[7, 0, 3, 1, 2, 4, 8, 6, 5]
[0, 7, 3, 1, 2, 4, 8, 6, 5]
[1, 7, 3, 0, 2, 4, 8, 6, 5]
[1, 7, 3, 8, 2, 4, 0, 6, 5]
[1, 7, 3, 8, 2, 4, 6, 0, 5]
[1, 7, 3, 8, 0, 4, 6, 2, 5]
[1, 0, 3, 8, 7, 4, 6, 2, 5]
[1, 3, 0, 8, 7, 4, 6, 2, 5]
[1, 3, 4, 8, 7, 0, 6, 2, 5]
[1, 3, 4, 8, 7, 5, 6, 2, 0]
[1, 3, 4, 8, 7, 5, 6, 0, 2]
[1, 3, 4, 8, 0, 5, 6, 7, 2]
[1, 3, 4, 8, 5, 0, 6, 7, 2]
[1, 3, 0, 8, 5, 4, 6, 7, 2]
[1, 0, 3, 8, 5, 4, 6, 7, 2]
[0, 1, 3, 8, 5, 4, 6, 7, 2]
[8, 1, 3, 0, 5, 4, 6, 7, 2]
[8, 1, 3, 5, 0, 4, 6, 7, 2]
成功!共搜索19层。
耗时0.3413248062133789s。

Process finished with exit code 0

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值