3

我用 Python 开发了自己的程序来解决 8 个谜题。最初,我使用“盲目”或不知情的搜索(基本上是暴力破解)生成和探索所有可能的继任者,并使用广度优先搜索。当它找到“目标”状态时,它基本上会回到初始状态并提供(我相信)是解决它的最优化步骤。当然,在某些初始状态下,搜索会花费大量时间并在找到目标之前生成超过 100,000 个状态。

然后我添加了启发式 - 曼哈顿距离。解决方案开始呈指数级增长,并且探索的状态要少得多。但我的困惑是,在某些时候,生成的优化序列比使用盲目或不知情的搜索所达到的要长。

我正在做的基本上是这样的:

  1. 对于每个状态,查找所有可能的移动(上、下、左和右),并生成后续状态。
  2. 检查状态是否重复。如果是,则忽略它。
  3. 计算该州的曼哈顿。
  4. 挑选出曼哈顿最低的继任者并添加到列表的末尾。
  5. 检查目标状态。如果是,则打破循环。

我不确定这是否符合贪婪优先或 A* 的条件。

我的问题是,这是曼哈顿距离启发式的固有缺陷,有时它不会给出最佳解决方案,或者我做错了什么。

下面是代码。我很抱歉这不是一个非常干净的代码,但主要是顺序的,应该很容易理解。我也为长代码道歉 - 我知道我需要优化它。也将不胜感激任何清理代码的建议/指导。这是什么:

import numpy as np
from copy import deepcopy
import sys

# calculate Manhattan distance for each digit as per goal
def mhd(s, g):
    m = abs(s // 3 - g // 3) + abs(s % 3 - g % 3)
    return sum(m[1:])

# assign each digit the coordinate to calculate Manhattan distance
def coor(s):
    c = np.array(range(9))
    for x, y in enumerate(s):
        c[y] = x
    return c

#################################################
def main():
    goal    =  np.array( [1, 2, 3, 4, 5, 6, 7, 8, 0] )
    rel     = np.array([-1])
    mov     = np.array([' '])
    string = '102468735'
    inf = 'B'
    pos = 0
    yes = 0
    goalc = coor(goal)
    puzzle = np.array([int(k) for k in string]).reshape(1, 9)
    rnk = np.array([mhd(coor(puzzle[0]), goalc)])
    while True:
        loc = np.where(puzzle[pos] == 0)        # locate '0' (blank) on the board
        loc = int(loc[0])
        child = np.array([], int).reshape(-1, 9)
        cmove = []
        crank = []
        # generate successors on possible moves - new states no repeats
        if loc > 2:         # if 'up' move is possible
            succ = deepcopy(puzzle[pos])
            succ[loc], succ[loc - 3] = succ[loc - 3], succ[loc]
            if ~(np.all(puzzle == succ, 1)).any():  # repeat state?
                child = np.append(child, [succ], 0)
                cmove.append('up')
                crank.append(mhd(coor(succ), goalc)) # manhattan distance
        if loc < 6:         # if 'down' move is possible
            succ = deepcopy(puzzle[pos])
            succ[loc], succ[loc + 3] = succ[loc + 3], succ[loc]
            if ~(np.all(puzzle == succ, 1)).any():  # repeat state?
                child = np.append(child, [succ], 0)
                cmove.append('down')
                crank.append(mhd(coor(succ), goalc))
        if loc % 3 != 0:    # if 'left' move is possible
            succ = deepcopy(puzzle[pos])
            succ[loc], succ[loc - 1] = succ[loc - 1], succ[loc]
            if ~(np.all(puzzle == succ, 1)).any():  # repeat state?
                child = np.append(child, [succ], 0)
                cmove.append('left')
                crank.append(mhd(coor(succ), goalc))
        if loc % 3 != 2:    # if 'right' move is possible
            succ = deepcopy(puzzle[pos])
            succ[loc], succ[loc + 1] = succ[loc + 1], succ[loc]
            if ~(np.all(puzzle == succ, 1)).any():  # repeat state?
                child = np.append(child, [succ], 0)
                cmove.append('right')
                crank.append(mhd(coor(succ), goalc))
        for s in range(len(child)):
            if (inf in 'Ii' and crank[s] == min(crank)) \
            or (inf in 'Bb'):
                puzzle = np.append(puzzle, [child[s]], 0)
                rel = np.append(rel, pos)
                mov = np.append(mov, cmove[s])
                rnk = np.append(rnk, crank[s])
                if np.array_equal(child[s], goal):
                    print()
                    print('Goal achieved!. Successors generated:', len(puzzle) - 1)
                    yes = 1
                    break
        if yes == 1:
            break
        pos += 1
    # generate optimized steps by back-tracking the steps to the initial state
    optimal = np.array([], int).reshape(-1, 9)
    last = len(puzzle) - 1
    optmov = []
    rank = []
    while last != -1:
        optimal = np.insert(optimal, 0, puzzle[last], 0)
        optmov.insert(0, mov[last])
        rank.insert(0, rnk[last])
        last = int(rel[last])

    # show optimized steps
    optimal = optimal.reshape(-1, 3, 3)
    print('Total optimized steps:', len(optimal) - 1)
    print()
    for s in range(len(optimal)):
        print('Move:', optmov[s])
        print(optimal[s])
        print('Manhattan Distance:', rank[s])
        print()
    print()

################################################################
# Main Program

if __name__ == '__main__':
    main()

如果您想检查,这里有一些初始状态和计算的优化步骤(上面的代码将提供此选项以在盲搜索与知情搜索之间进行选择)

初始状态
- 283164507 盲人:19 曼哈顿:21
- 243780615 盲人:15 曼哈顿:21
- 102468735 盲人:11 曼哈顿:17
- 481520763 盲人:13 曼哈顿:23
- 723156480 盲人:16 曼哈顿:20

我特意选择了结果很快(几秒钟或几分钟内)的例子。

您的帮助和指导将不胜感激。

编辑:我做了一些快速更改并设法减少了大约 30 多行。不幸的是,此时不能做太多事情。
注意:我已经硬编码了初始状态和盲目与知情选择。请更改初始状态的变量“string”的值和 Informed/Blind 的变量“inf”[I/B] 的值。谢谢!

4

0 回答 0