A*算法求解八数码问题实验(详细附代码)

一、实验目的

熟悉和掌握启发式搜索的定义、估价函数和算法过程,并利用A*算法求解 N数码难题,理解求解流程和搜索顺序。

二、实验内容

以8数码问题为例实现 A*算法的求解程序(编程语言不限,如Python等)要求设计两种不同的估价函数。

三、实验要求

1.设置相同的初始状态和目标状态,针对不同的估价函数,求得问题的解,比较它们对搜索算法性能的影响,包括扩展节点数等,填入下表。

下面以我做的实验为例:

初始状态:1 3 2   4 5 6    8 0 7                           目的状态:  1 2 3    4 5 6    7 8 0

注:耗时在每个人的电脑上数据不同

实验结果如下表:

算法

启发函数h(n)

搜索步数

生成节点数

耗时

宽度优先

 /

19

106176

10126.424312591553ms

A*

不在位数

29

5739

574.6653079986572ms

A*

哈密尔顿距离

35

808

100.56138038635254ms

下面给出三种情况的代码:

1、启发函数  /

​
import numpy as np
import time


class State:
    def __init__(self, state, directionFlag=None, parent=None, f=0):
        self.state = state
        self.direction = ['up', 'down', 'right', 'left']
        if directionFlag:
            self.direction.remove(directionFlag)
        self.parent = parent
        self.f = f

    def getDirection(self):
        return self.direction

    def setF(self, f):
        self.f = f
        return

    # 打印结果
    def showInfo(self):
        for i in range(len(self.state)):
            for j in range(len(self.state)):
                print(self.state[i, j], end='  ')
            print("\n")
        print('->')
        return

    # 获取0点
    def getZeroPos(self):
        postion = np.where(self.state == 0)
        return postion

    # 曼哈顿距离  f = g + h,g+1
    def getFunctionValue(self):
        cur_node = self.state.copy()
        fin_node = self.answer.copy()
        dist = 0
        N = len(cur_node)

        for i in range(N):
            for j in range(N):
                if cur_node[i][j] != fin_node[i][j]:
                    index = np.argwhere(fin_node == cur_node[i][j])
                    dist += 1

        return dist + 1

    def nextStep(self):
        if not self.direction:
            return []
        subStates = []
        boarder = len(self.state) - 1
        # 获取0点位置;x是行,y是列
        x, y = self.getZeroPos()
        # 向左
        if 'left' in self.direction and y > 0:
            s = self.state.copy()
            tmp = s[x, y - 1]
            s[x, y - 1] = s[x, y]
            s[x, y] = tmp
            news = State(s, directionFlag='right', parent=self)
            news.setF(news.getFunctionValue())
            subStates.append(news)
        # 向上
        if 'up' in self.direction and x > 0:
            # it can move to upper place
            s = self.state.copy()
            tmp = s[x - 1, y]
            s[x - 1, y] = s[x, y]
            s[x, y] = tmp
            news = State(s, directionFlag='down', parent=self)
            news.setF(news.getFunctionValue())
            subStates.append(news)
        # 向下
        if 'down' in self.direction and x < boarder:
            # it can move to down place
            s = self.state.copy()
            tmp = s[x + 1, y]
            s[x + 1, y] = s[x, y]
            s[x, y] = tmp
            news = State(s, directionFlag='up', parent=self)
            news.setF(news.getFunctionValue())
            subStates.append(news)
        # 向右
        if self.direction.count('right') and y < boarder:
            # it can move to right place
            s = self.state.copy()
            tmp = s[x, y + 1]
            s[x, y + 1] = s[x, y]
            s[x, y] = tmp
            news = State(s, directionFlag='left', parent=self)
            news.setF(news.getFunctionValue())
            subStates.append(news)

        return subStates

    # A* 迭代
    def solve(self):

        openTable.append(self)

        while len(openTable) > 0:
            openTable.sort(key=compareNum) 
            # 下一步的点移除open
            n = openTable.pop(0)
            # 加入close
            closeTable.append(n)

            # 确定下一步点
            subStates = n.nextStep()
            path = []

            for subSta in subStates:
                if (subSta.state == subSta.answer).all():
                    ansStates = subSta
                    while ansStates.parent and ansStates.parent != originState:
                        path.append(ansStates.parent)
                        ansStates = ansStates.parent
                    path.reverse()
                    return path
                openTable.append(subSta)
        else:
            return None, None


def compareNum(state):
    return state.f


if __name__ == '__main__':
    # originState = State(np.array([[1,5, 3], [2, 4, 6], [7, 0, 8]]))
    # originState = State(np.array([[1, 2, 3], [5, 4, 6], [8, 0, 7]]))
    originState = State(np.array([[1, 3, 2], [4, 5, 6], [8, 0, 7]]))

    State.answer = np.array([[1, 2, 3], [4, 5, 6], [7, 8, 0]])
    # originState = State(np.array([[2, 8, 3], [ 6,0,4], [1,7, 5]]))
    # State.answer = np.array([[1, 2, 3], [8, 0, 4], [7, 6, 5]])

    s1 = State(state=originState.state)
    s_time = time.time()
    # openList
    openTable = []
    # closeList
    closeTable = []
    path = s1.solve()
    if path:
        for node in path:
            node.showInfo()

        print(State.answer)
        print("Total time is (ms):", (time.time() - s_time) * 1000)
        print("Total extend nodes:%d" % (len(closeTable) + len(openTable)))
        print("Total steps is %d" % len(path))


​

2、不在位数

​
import numpy as np
import time


class State:
    def __init__(self, state, directionFlag=None, parent=None, f=0):
        self.state = state
        self.direction = ['up', 'down', 'right', 'left']
        if directionFlag:
            self.direction.remove(directionFlag)
        self.parent = parent
        self.f = f

    def getDirection(self):
        return self.direction

    def setF(self, f):
        self.f = f
        return

    # 打印结果
    def showInfo(self):
        for i in range(len(self.state)):
            for j in range(len(self.state)):
                print(self.state[i, j], end='  ')
            print("\n")
        print('->')
        return

    # 获取0点
    def getZeroPos(self):
        postion = np.where(self.state == 0)
        return postion

    # 曼哈顿距离  f = g + h,g+1
    def getFunctionValue(self):
        cur_node = self.state.copy()
        fin_node = self.answer.copy()
        dist = 0
        N = len(cur_node)

        for i in range(N):
            for j in range(N):
                if cur_node[i][j] != fin_node[i][j]:
                    index = np.argwhere(fin_node == cur_node[i][j])
                    dist += (abs(x - i) + abs(y - j))

        return dist + 1

    def nextStep(self):
        if not self.direction:
            return []
        subStates = []
        boarder = len(self.state) - 1
        # 获取0点位置;x是行,y是列
        x, y = self.getZeroPos()
        # 向左
        if 'left' in self.direction and y > 0:
            s = self.state.copy()
            tmp = s[x, y - 1]
            s[x, y - 1] = s[x, y]
            s[x, y] = tmp
            news = State(s, directionFlag='right', parent=self)
            news.setF(news.getFunctionValue())
            subStates.append(news)
        # 向上
        if 'up' in self.direction and x > 0:
            # it can move to upper place
            s = self.state.copy()
            tmp = s[x - 1, y]
            s[x - 1, y] = s[x, y]
            s[x, y] = tmp
            news = State(s, directionFlag='down', parent=self)
            news.setF(news.getFunctionValue())
            subStates.append(news)
        # 向下
        if 'down' in self.direction and x < boarder:
            # it can move to down place
            s = self.state.copy()
            tmp = s[x + 1, y]
            s[x + 1, y] = s[x, y]
            s[x, y] = tmp
            news = State(s, directionFlag='up', parent=self)
            news.setF(news.getFunctionValue())
            subStates.append(news)
        # 向右
        if self.direction.count('right') and y < boarder:
            # it can move to right place
            s = self.state.copy()
            tmp = s[x, y + 1]
            s[x, y + 1] = s[x, y]
            s[x, y] = tmp
            news = State(s, directionFlag='left', parent=self)
            news.setF(news.getFunctionValue())
            subStates.append(news)

        return subStates

    # A* 迭代
    def solve(self):

        openTable.append(self)

        while len(openTable) > 0:
            # 下一步的点移除open
            n = openTable.pop(0)
            # 加入close
            closeTable.append(n)

            # 确定下一步点
            subStates = n.nextStep()
            path = []

            for subSta in subStates:
                if (subSta.state == subSta.answer).all():
                    ansStates = subSta
                    while ansStates.parent and ansStates.parent != originState:
                        path.append(ansStates.parent)
                        ansStates = ansStates.parent
                    path.reverse()
                    return path
                openTable.append(subSta)
        else:
            return None, None


def compareNum(state):
    return state.f


if __name__ == '__main__':
    # originState = State(np.array([[1,5, 3], [2, 4, 6], [7, 0, 8]]))
    # originState = State(np.array([[1, 2, 3], [5, 4, 6], [8, 0, 7]]))
    originState = State(np.array([[1, 3, 2], [4, 5, 6], [8, 0, 7]]))

    State.answer = np.array([[1, 2, 3], [4, 5, 6], [7, 8, 0]])
    # originState = State(np.array([[2, 8, 3], [ 6,0,4], [1,7, 5]]))
    # State.answer = np.array([[1, 2, 3], [8, 0, 4], [7, 6, 5]])

    s1 = State(state=originState.state)
    s_time = time.time()
    # openList
    openTable = []
    # closeList
    closeTable = []
    path = s1.solve()
    if path:
        for node in path:
            node.showInfo()

        print(State.answer)
        print("Total time is (ms):", (time.time() - s_time) * 1000)
        print("Total extend nodes:%d" % (len(closeTable) + len(openTable)))
        print("Total steps is %d" % len(path))


​

3、哈密尔顿距离

import numpy as np
import time


class State:
    def __init__(self, state, directionFlag=None, parent=None, f=0):
        self.state = state
        self.direction = ['up', 'down', 'right', 'left']
        if directionFlag:
            self.direction.remove(directionFlag)
        self.parent = parent
        self.f = f

    def getDirection(self):
        return self.direction

    def setF(self, f):
        self.f = f
        return

    # 打印结果
    def showInfo(self):
        for i in range(len(self.state)):
            for j in range(len(self.state)):
                print(self.state[i, j], end='  ')
            print("\n")
        print('->')
        return

    # 获取0点
    def getZeroPos(self):
        postion = np.where(self.state == 0)
        return postion

    # 曼哈顿距离  f = g + h,g+1
    def getFunctionValue(self):
        cur_node = self.state.copy()
        fin_node = self.answer.copy()
        dist = 0
        N = len(cur_node)

        for i in range(N):
            for j in range(N):
                if cur_node[i][j] != fin_node[i][j]:
                    index = np.argwhere(fin_node == cur_node[i][j])
                    x = index[0][0]  # 最终x距离
                    y = index[0][1]  # 最终y距离
                    dist += (abs(x - i) + abs(y - j))
                    

        return dist + 1

    def nextStep(self):
        if not self.direction:
            return []
        subStates = []
        boarder = len(self.state) - 1
        # 获取0点位置;x是行,y是列
        x, y = self.getZeroPos()
        # 向左
        if 'left' in self.direction and y > 0:
            s = self.state.copy()
            tmp = s[x, y - 1]
            s[x, y - 1] = s[x, y]
            s[x, y] = tmp
            news = State(s, directionFlag='right', parent=self)
            news.setF(news.getFunctionValue())
            subStates.append(news)
        # 向上
        if 'up' in self.direction and x > 0:
            # it can move to upper place
            s = self.state.copy()
            tmp = s[x - 1, y]
            s[x - 1, y] = s[x, y]
            s[x, y] = tmp
            news = State(s, directionFlag='down', parent=self)
            news.setF(news.getFunctionValue())
            subStates.append(news)
        # 向下
        if 'down' in self.direction and x < boarder:
            # it can move to down place
            s = self.state.copy()
            tmp = s[x + 1, y]
            s[x + 1, y] = s[x, y]
            s[x, y] = tmp
            news = State(s, directionFlag='up', parent=self)
            news.setF(news.getFunctionValue())
            subStates.append(news)
        # 向右
        if self.direction.count('right') and y < boarder:
            # it can move to right place
            s = self.state.copy()
            tmp = s[x, y + 1]
            s[x, y + 1] = s[x, y]
            s[x, y] = tmp
            news = State(s, directionFlag='left', parent=self)
            news.setF(news.getFunctionValue())
            subStates.append(news)

        return subStates

    # A* 迭代
    def solve(self):

        openTable.append(self)

        while len(openTable) > 0:
            openTable.sort(key=compareNum) 
            # 下一步的点移除open
            n = openTable.pop(0)
            # 加入close
            closeTable.append(n)

            # 确定下一步点
            subStates = n.nextStep()
            path = []

            for subSta in subStates:
                if (subSta.state == subSta.answer).all():
                    ansStates = subSta
                    while ansStates.parent and ansStates.parent != originState:
                        path.append(ansStates.parent)
                        ansStates = ansStates.parent
                    path.reverse()
                    return path
                openTable.append(subSta)
        else:
            return None, None


def compareNum(state):
    return state.f


if __name__ == '__main__':
    # originState = State(np.array([[1,5, 3], [2, 4, 6], [7, 0, 8]]))
    # originState = State(np.array([[1, 2, 3], [5, 4, 6], [8, 0, 7]]))
    originState = State(np.array([[1, 3, 2], [4, 5, 6], [8, 0, 7]]))

    State.answer = np.array([[1, 2, 3], [4, 5, 6], [7, 8, 0]])
    # originState = State(np.array([[2, 8, 3], [ 6,0,4], [1,7, 5]]))
    # State.answer = np.array([[1, 2, 3], [8, 0, 4], [7, 6, 5]])

    s1 = State(state=originState.state)
    s_time = time.time()
    # openList
    openTable = []
    # closeList
    closeTable = []
    path = s1.solve()
    if path:
        for node in path:
            node.showInfo()

        print(State.answer)
        print("Total time is (ms):", (time.time() - s_time) * 1000)
        print("Total extend nodes:%d" % (len(closeTable) + len(openTable)))
        print("Total steps is %d" % len(path))

你可能感兴趣的:(算法,python,开发语言)