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))

  • 15
    点赞
  • 137
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
include using namespace std; struct node{ int nodesun[4][4]; int pre; //上一步在队列中的位置 int flag ; //步数标识,表示当前的步数为有效的 int value; //与目标的差距 int x,y; //空格坐标 }queue[1000]; //移动方向数组 int zx[4]={-1,0,1,0}; int zy[4]={0,-1,0,1}; //当前步数 int top; int desti[4][4];//目标状态 int detect(struct node *p)//检查是否找到 {int i,j; for(i=1;i<4;i++) for(j=1;jnodesun[i][j]!=desti[i][j]) return 0; return 1; } //打印 void printlj() {int tempt; int i,j; tempt=top; while(tempt!=0) { for(i=1;i<4;i++) for(j=1;j<4;j++) {cout<<queue[tempt].nodesun[i][j]; if(j==3) cout<<" "<<endl; } tempt=queue[tempt].pre; } } //现在状态与目标状态有多少个不同位置 int VALUE(struct node *p) {int count=0; int i,j; for(i=1;i<4;i++) for(j=1;jnodesun[i][j]!=desti[i][j]) count++; return count; } void main() { //初始化 int i,j,m,n,f; int min=10; int temp,find=0,minnumber; top=1; for(i=1;i<4;i++) for(j=1;j<4;j++) {cout<<"请输入第"<<i<<"行"<<"第"<<j<<"列的值"<>temp; queue[1].nodesun[i][j]=temp; } cout<<"请输入初始状态的空格的位置(行)"<>temp; queue[1].x=temp; cout<<"请输入初始状态的空格的位置(列)"<>temp; queue[1].y=temp; queue[1].value=VALUE(&queue[1]); queue[1].pre=0; //上一步在队列中的位置 queue[1].flag=0; //目标状态 for(i=1;i<4;i++) for(j=1;j<4;j++) {cout<<"请输入目标状态第"<<i<<"行"<<"第"<<j<<"列的值"<>temp; desti[i][j]=temp; } //根据估价函数 while(!find&&top>0) { for(i=1;i<=top;i++) //////////////////////////////////////////// //min为上一图中与目标图有多少个元素不相同,queue[i]为当前图与目标图有多少个元素不相同通过这两个数的比较,就可以得出当前图较之上一图向目标图接近同时把当前的i记录下来进行下一步比较 {if(queue[i].value<min&&queue[i].flag==0) {minnumber=i;// min=queue[i].value; //还有多少不同的位数 } } queue[minnumber].flag=1; //表示此位有效 ////////////////////////////////////// // for(f=0;f=1&&i=1&&j<=3) {top++; ///////////////////////////////////////////// //位置交换 queue[top]=queue[minnumber]; queue[top].nodesun[m][n]=queue[minnumber].nodesun[i][j]; queue[top].nodesun[i][j]=0; /////////////////////////////////////// //空格移动方向 queue[top].x=i; queue[top].y=j; /////////////////////////////////////// queue[top].pre=minnumber; //上一步在队列中的位置 queue[top].value=VALUE(&queue[top]); //有多少位与目标不同 queue[top].flag=0; //标识位初始化 if(detect(&queue[top])) //检查是否为目标 {printlj(); //打印 find=1; //设找到标识位 break; } } } } }
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值