2020-11-14

95 篇文章 2 订阅

八数码问题——持续更新中(一)

最近一段时间一直在思考,没有时间写东西……
现在能够短暂坐下来,还是把前面的程序改改。
八数码问题已经写了多篇,但仍然感到意犹未尽。
其实双向搜索还是可行的。只是当时认为搜索的层数比较多,觉得这个程序的适应性比较差。但随着认识的变化,这个程序的重要性凸显出来,于是又回过头来对这个程序进行修订,暂且不提。
认识的变化还在于最多需要搜索多少层上。
有部分证据说明最多搜索不会超过30层。
基本验证思路是这样的:选定目标状态(target),然后对其他状态(original)进行遍历,筛选那些可以变化到目标状态的所有组合,计算他们(target状态与original状态)之间的曼哈顿距离,结论是最大不超过24。对这些曼哈顿距离达到24的所有组合逐一进行由始至终的层次计算。经过一段时间的运算,没有发现层次超过30的案例!虽然这个验证的过程或许有瑕疵,没有把曼哈顿距离小于24的情况进行逐一验证,但基本可以肯定,结论是正确的。
下面是完整的程序代码:

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


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


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


# 代价计算,计算当前状态与目标状态间的曼哈顿距离,作为第一排序的依据,是优选种子的关键
def manhattan(state):
    _count = 0
    for _i in range(9):
        if target[_i] != 0:
            for _j in range(9):
                if state[_j] == target[_i]:
                    _count += abs(_j % 3 - _i % 3) + abs(_j // 3 - _i // 3)
                    break
    return _count


# 计算当前状态与目标状态的差异值,作为第二排序的依据
def diff(state):
    _diff = 0
    for _i in range(9):
        if state[_i] != target[_i]:
            _diff += 1
    return _diff


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

    t0 = time.time()
    b = [0, 1, 2, 3, 4, 5, 6, 7, 8]
    target = [1, 2, 3, 4, 0, 5, 6, 7, 8]
    # 记录空格(0)从一个状态(位置)变化到下一个状态(位置)信息,在原来的基础上进行了精简
    base = [[1, 3], [0, 2, 4], [1, 5], [0, 4, 6], [1, 3, 5, 7], [2, 4, 8], [3, 7], [4, 6, 8], [5, 7]]
    all_combinations = itertools.permutations(b, 9)
    number = 0  # 统计搜索层次等于或大于30的数量
    count = 0  # 统计曼哈顿距离达到24的组合数量
    c2 = solution(target)
    for original in all_combinations:
        sum_list = []  # 存放记录状态链表数据
        mark = 0
        c1 = solution(original)
        if (c1 + c2) % 2 != 0:
            continue
        if manhattan(original) == 24:
            count += 1
            source = original
            seed, layer = [source], 1
            while True:
                for f in seed:
                    L = Lists(layer, f)  # 实例化链表类
                    for t in L.sun:
                        if t == target:
                            mark = 1
                            if layer >= 30:
                                number += 1
                                print(original)
                                print("共搜索{}层。".format(layer))
                            break
                    if mark == 1:
                        break
                    # 去重
                    for s in sum_list:
                        if s.storey == layer - 1 and s.father in L.sun:
                            L.sun.remove(s.father)
                            break
                    sum_list.append(L)
                if mark == 1:
                    break
                # 优选种子
                seed, see = [], []
                for i in sum_list:
                    if i.storey == layer:
                        seed.extend(i.sun)
                # 再去重
                for se in seed:
                    if se not in see:
                        see.append(se)
                # 以曼哈顿距离为第一排序,距离越短,排序越靠前;以差异值作为第二排序,差异值越小,排序越靠前,排序300以后的舍去
                see = sorted(see, key=lambda k: manhattan(k) - diff(k))
                seed = see[:300]
                layer += 1
    print("曼哈顿距离达到24的组合数量为{}。".format(count))
    print("共有{}种组合,其搜索层次等于或大于30。".format(number))
    print("耗时{}s。".format(time.time() - t0))

D:\Python\Python38\python.exe D:/Python/study/egiht7.py
(5, 4, 6, 8, 0, 7, 3, 2, 1)
共搜索30层。
(5, 6, 7, 8, 0, 1, 2, 3, 4)
共搜索30层。
(5, 7, 6, 8, 0, 1, 3, 2, 4)
共搜索30层。
(7, 8, 4, 3, 0, 6, 5, 1, 2)
共搜索30层。
(7, 8, 6, 2, 0, 4, 3, 5, 1)
共搜索30层。
(7, 8, 6, 5, 0, 4, 3, 1, 2)
共搜索30层。
(8, 4, 6, 2, 0, 7, 3, 5, 1)
共搜索30层。
(8, 4, 6, 5, 0, 7, 3, 1, 2)
共搜索30层。
(8, 5, 4, 7, 0, 6, 3, 2, 1)
共搜索30层。
(8, 5, 6, 7, 0, 2, 3, 4, 1)
共搜索30层。
(8, 5, 6, 7, 0, 4, 2, 3, 1)
共搜索30层。
(8, 6, 7, 5, 0, 2, 3, 4, 1)
共搜索30层。
(8, 6, 7, 5, 0, 4, 2, 3, 1)
共搜索30层。
(8, 7, 4, 3, 0, 6, 5, 2, 1)
共搜索30层。
(8, 7, 6, 2, 0, 1, 3, 5, 4)
共搜索30层。
(8, 7, 6, 3, 0, 2, 5, 4, 1)
共搜索30层。
(8, 7, 6, 5, 0, 4, 3, 2, 1)
共搜索30层。
曼哈顿距离达到24的组合数量为97。
共有17种组合,其搜索层次等于或大于30。
耗时279.3544330596924s。

Process finished with exit code 0

通过上述测试,发现一个现象,在曼哈顿距离达到24的组合中,凡须要运算30层的组合,其original状态当中的“0”都是处于中间位置,并且target状态中的“0”也处于中间位置,否则无须30层就能搞定!读者可以自行验算。也就是说,在曼哈顿距离达到24的组合中,只要target或original当中的“0”有一个不在中间,运算层次就可以控制在30层以下!但不能就此肯定只有曼哈顿距离达到24的组合,才有可能须要运算到30层。有下面的案例为证:
source = [0, 4, 6, 5, 8, 7, 3, 2, 1]
target = [1, 2, 3, 4, 0, 5, 6, 7, 8]
它们的曼哈顿距离只有22,但运算层次达到了30层。

中午吃饭的时候把程序稍作修改测试了曼哈顿距离为23时,层次达到或超过29的情况,发现original中的“0”果然都不在中间,并且最大只有29层。

D:\Python\Python38\python.exe D:/Python/study/egiht7.py
(5, 0, 6, 2, 8, 7, 3, 4, 1)
共搜索29层。
(5, 0, 6, 8, 4, 7, 3, 2, 1)
共搜索29层。
(5, 0, 6, 8, 7, 1, 3, 2, 4)
共搜索29层。
(5, 0, 6, 8, 7, 4, 3, 1, 2)
共搜索29层。
(5, 4, 6, 0, 8, 7, 3, 2, 1)
共搜索29层。
(5, 4, 6, 8, 2, 7, 3, 0, 1)
共搜索29层。
(5, 4, 6, 8, 7, 0, 3, 2, 1)
共搜索29层。
(5, 7, 6, 0, 8, 1, 3, 2, 4)
共搜索29层。
(5, 7, 6, 8, 1, 0, 3, 2, 4)
共搜索29层。
(5, 7, 6, 8, 2, 0, 3, 4, 1)
共搜索29层。
(5, 7, 6, 8, 2, 1, 3, 0, 4)
共搜索29层。
(5, 7, 6, 8, 4, 0, 3, 1, 2)
共搜索29层。
(5, 7, 6, 8, 4, 2, 3, 0, 1)
共搜索29层。
(7, 0, 6, 2, 8, 4, 3, 5, 1)
共搜索29层。
(7, 0, 6, 5, 8, 4, 3, 1, 2)
共搜索29层。
(7, 4, 6, 0, 8, 2, 3, 5, 1)
共搜索29层。
(7, 8, 6, 0, 2, 4, 3, 5, 1)
共搜索29层。
(7, 8, 6, 0, 5, 1, 3, 2, 4)
共搜索29层。
(7, 8, 6, 0, 5, 4, 3, 1, 2)
共搜索29层。
(7, 8, 6, 2, 4, 0, 3, 5, 1)
共搜索29层。
(7, 8, 6, 2, 5, 4, 3, 0, 1)
共搜索29层。
(7, 8, 6, 5, 1, 4, 3, 0, 2)
共搜索29层。
(7, 8, 6, 5, 2, 0, 3, 4, 1)
共搜索29层。
(7, 8, 6, 5, 2, 1, 3, 0, 4)
共搜索29层。
(7, 8, 6, 5, 4, 0, 3, 1, 2)
共搜索29层。
(7, 8, 6, 5, 4, 2, 3, 0, 1)
共搜索29层。
(8, 0, 4, 3, 7, 6, 5, 2, 1)
共搜索29层。
(8, 0, 4, 5, 7, 6, 2, 3, 1)
共搜索29层。
(8, 0, 4, 7, 5, 6, 3, 2, 1)
共搜索29层。
(8, 0, 4, 7, 6, 2, 3, 5, 1)
共搜索29层。
(8, 0, 6, 2, 4, 7, 3, 5, 1)
共搜索29层。
(8, 0, 6, 2, 7, 1, 3, 5, 4)
共搜索29层。
(8, 0, 6, 3, 4, 7, 5, 2, 1)
共搜索29层。
(8, 0, 6, 3, 7, 2, 5, 4, 1)
共搜索29层。
(8, 0, 6, 5, 2, 7, 3, 4, 1)
共搜索29层。
(8, 0, 6, 5, 4, 7, 2, 3, 1)
共搜索29层。
(8, 0, 6, 5, 4, 7, 3, 1, 2)
共搜索29层。
(8, 0, 6, 5, 7, 4, 3, 2, 1)
共搜索29层。
(8, 0, 6, 7, 2, 4, 3, 5, 1)
共搜索29层。
(8, 0, 6, 7, 5, 1, 3, 2, 4)
共搜索29层。
(8, 0, 6, 7, 5, 2, 3, 4, 1)
共搜索29层。
(8, 0, 6, 7, 5, 4, 2, 3, 1)
共搜索29层。
(8, 0, 6, 7, 5, 4, 3, 1, 2)
共搜索29层。
(8, 0, 7, 5, 6, 2, 3, 4, 1)
共搜索29层。
(8, 0, 7, 5, 6, 4, 2, 3, 1)
共搜索29层。
(8, 4, 6, 0, 2, 7, 3, 5, 1)
共搜索29层。
(8, 4, 6, 0, 5, 7, 3, 1, 2)
共搜索29层。
(8, 4, 6, 2, 5, 7, 3, 0, 1)
共搜索29层。
(8, 4, 6, 2, 7, 0, 3, 5, 1)
共搜索29层。
(8, 4, 6, 3, 7, 0, 5, 2, 1)
共搜索29层。
(8, 4, 6, 5, 1, 7, 3, 0, 2)
共搜索29层。
(8, 4, 6, 5, 7, 0, 2, 3, 1)
共搜索29层。
(8, 4, 6, 5, 7, 0, 3, 1, 2)
共搜索29层。
(8, 4, 6, 5, 7, 2, 3, 0, 1)
共搜索29层。
(8, 4, 6, 7, 1, 0, 3, 5, 2)
共搜索29层。
(8, 4, 6, 7, 3, 2, 5, 0, 1)
共搜索29层。
(8, 4, 6, 7, 5, 0, 3, 2, 1)
共搜索29层。
(8, 5, 4, 0, 7, 6, 3, 2, 1)
共搜索29层。
(8, 5, 4, 7, 2, 6, 3, 0, 1)
共搜索29层。
(8, 5, 4, 7, 6, 0, 3, 2, 1)
共搜索29层。
(8, 5, 6, 0, 3, 7, 2, 4, 1)
共搜索29层。
(8, 5, 6, 0, 4, 7, 3, 2, 1)
共搜索29层。
(8, 5, 6, 0, 7, 1, 3, 2, 4)
共搜索29层。
(8, 5, 6, 0, 7, 2, 3, 4, 1)
共搜索29层。
(8, 5, 6, 0, 7, 4, 2, 3, 1)
共搜索29层。
(8, 5, 6, 0, 7, 4, 3, 1, 2)
共搜索29层。
(8, 5, 6, 2, 1, 7, 3, 0, 4)
共搜索29层。
(8, 5, 6, 2, 7, 4, 3, 0, 1)
共搜索29层。
(8, 5, 6, 7, 2, 0, 3, 4, 1)
共搜索29层。
(8, 5, 6, 7, 3, 4, 2, 0, 1)
共搜索29层。
(8, 5, 6, 7, 4, 0, 2, 3, 1)
共搜索29层。
(8, 5, 6, 7, 4, 2, 3, 0, 1)
共搜索29层。
(8, 5, 7, 2, 6, 0, 3, 4, 1)
共搜索29层。
(8, 6, 7, 0, 2, 4, 3, 5, 1)
共搜索29层。
(8, 6, 7, 0, 5, 2, 3, 4, 1)
共搜索29层。
(8, 6, 7, 0, 5, 4, 2, 3, 1)
共搜索29层。
(8, 6, 7, 2, 5, 4, 3, 0, 1)
共搜索29层。
(8, 6, 7, 3, 2, 4, 5, 0, 1)
共搜索29层。
(8, 6, 7, 3, 4, 0, 5, 2, 1)
共搜索29层。
(8, 6, 7, 5, 2, 0, 3, 4, 1)
共搜索29层。
(8, 6, 7, 5, 3, 4, 2, 0, 1)
共搜索29层。
(8, 6, 7, 5, 4, 0, 2, 3, 1)
共搜索29层。
(8, 6, 7, 5, 4, 2, 3, 0, 1)
共搜索29层。
(8, 7, 4, 0, 2, 6, 3, 5, 1)
共搜索29层。
(8, 7, 4, 0, 3, 6, 5, 2, 1)
共搜索29层。
(8, 7, 4, 0, 5, 6, 2, 3, 1)
共搜索29层。
(8, 7, 4, 2, 5, 6, 3, 0, 1)
共搜索29层。
(8, 7, 4, 3, 2, 6, 5, 0, 1)
共搜索29层。
(8, 7, 4, 3, 6, 0, 5, 2, 1)
共搜索29层。
(8, 7, 6, 0, 2, 1, 3, 5, 4)
共搜索29层。
(8, 7, 6, 0, 3, 2, 5, 4, 1)
共搜索29层。
(8, 7, 6, 0, 4, 2, 3, 5, 1)
共搜索29层。
(8, 7, 6, 0, 5, 4, 3, 2, 1)
共搜索29层。
(8, 7, 6, 2, 1, 0, 3, 5, 4)
共搜索29层。
(8, 7, 6, 2, 5, 0, 3, 4, 1)
共搜索29层。
(8, 7, 6, 2, 5, 1, 3, 0, 4)
共搜索29层。
(8, 7, 6, 3, 2, 0, 5, 4, 1)
共搜索29层。
(8, 7, 6, 3, 4, 2, 5, 0, 1)
共搜索29层。
(8, 7, 6, 5, 2, 4, 3, 0, 1)
共搜索29层。
(8, 7, 6, 5, 4, 0, 3, 2, 1)
共搜索29层。
曼哈顿距离达到23的组合数量为572。
共有100种组合,其搜索层次等于或大于29。
耗时1654.776507616043s。

Process finished with exit code 0

要说明二点。其一,这次曼哈顿距离计算把“0”排除在外,感觉效率更高,种选300即可。是否有例外还不清楚,如果有,可以采用双向搜索重新验证一下。其二,对种子进行了去重处理,效果不错。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值