A*算法求解N数码

Posted 是一个小迷糊吧

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了A*算法求解N数码相关的知识,希望对你有一定的参考价值。

A*算法实验

实验目的:

1.熟悉启发式搜索的定义、估价函数和算法过程
2.利用A*算法求解N数码难题,理解求解流程和搜索顺序
3.熟练掌握numpy库的相关函数(单独库,需要使用‘pip install numpy’安装)

实验原理:

A*算法是一种启发式图搜索算法,其特点在于对估价函数的定义上。对于一般的启发式图搜索,总是选择估价函数f值最小的节点作为扩展节点。因此,f是根据需要找到一条最小代价路径的观点来估算节点的,所以,可考虑每个节点n的估价函数值为两个分量:从起始节点到节点n的实际代价以及从节点n到达目标节点的估价代价。

实验内容:

1 、以8数码问题为例实现A*算法的求解程序。

估价函数f(n) = g(n) + h(n)
g(n)=d(n)——结点n在搜索树中的深度
h(n)可选择h1(n)——结点n中“不在位”的数码个数 或 h2(n) =p(n)= 将牌“不在位”的距离和

代码实现:

import numpy as np
def change (str):#提取输入到数字,合成数组
    list=[]
    for i in range(0,len(str)):
        list.append(str[i])
    a = np.array(list)
    b = a.reshape(hang,lie)
    return b
def h(newnumber,endnumber):#计算两个数码间位置不同的数字的个数
    h=0
    for i in range(0,hang):
        for j in range(0,lie):
            if (newnumber[i][j]!=endnumber[i][j]):
                h+=1
            else:
                continue
    return h
def g(newnumber,endnumber):#计算每个数字最近的路径之和
    g=0
    for i in range(0,hang):
        for j in range(0,lie):
            if (newnumber[i][j]!=endnumber[i][j]):
                g+=((abs((i-end[newnumber[i][j]][0])))+(abs((j-end[newnumber[i][j]][1]))))
            else:
                continue
    return g
def kongid(newnumber):#判断空格的位置
    for i in range(0,hang):
        for j in range(0,lie):
            if (newnumber[i][j]==' '):
                id=(i,j)
                return id
def same(newnumber,endnumber):#比较两个数组是否相等,相等返回True,不相等返回False
    a=(newnumber==endnumber)
    e=a.all()
    if(e):
        return True
    else:
        return False
def A(newnumber,endnumber):#变化N字码
   if (same(newnumber,endnumber)):
       return True
   else:
       xx=hang*lie*10
       l1n=xx
       l2n=xx
       l3n=xx
       l4n=xx
       a=kongid(newnumber)
       l1=newnumber.copy()
       l2=newnumber.copy()
       l3=newnumber.copy()
       l4=newnumber.copy()
       l0=newnumber[a[0]][a[1]]
       if((a[0]-1)>=0):
           l1[a[0]][a[1]]=newnumber[a[0]-1][a[1]]
           l1[a[0]-1][a[1]]=l0
           l1h=h(l1,endnumber)
           l1g=g(l1,endnumber)
           l1n=l1g+l1h
       if((a[0]+1)<=(hang-1)):
           l2[a[0]][a[1]]=newnumber[a[0]+1][a[1]]
           l2[a[0]+1][a[1]]=l0
           l2h=h(l2,endnumber)
           l2g=g(l2,endnumber)
           l2n=l2g+l2h
       if((a[1]-1)>=0):
           l3[a[0]][a[1]]=newnumber[a[0]][a[1]-1]
           l3[a[0]][a[1]-1]=l0
           l3h=h(l3,endnumber)
           l3g=g(l3,endnumber)
           l3n=l3g+l3h
       if((a[1]+1)<=(lie-1)):
           l4[a[0]][a[1]]=newnumber[a[0]][a[1]+1]
           l4[a[0]][a[1]+1]=l0
           l4h=h(l4,endnumber)
           l4g=g(l4,endnumber)
           l4n=l4g+l4h
       return [l1,l2,l3,l4,l1n,l2n,l3n,l4n]
while (True):
    str=input("输入要变化的数码问题的顺序(数据自左到右,自上到下):")
    str1=input("输入变化后的数码问题的顺序(数据自左到右,自上到下):")
    heng=input("输入数码的行数:")
    shu=input("输入数码的列数:")
    hang=int(heng)
    lie=int(shu)
    if ((hang*lie)==len(str) and ((hang*lie)==len(str1))):
        break
    else:
        if (hang*lie)==len(str):
            print("要变化的数码问题错误,返回至输入项——>>>")
        elif ((hang*lie)==len(str1)):
            print("输入的变化后的数码错误,返回至输入项——>>>")
        else:
            print("数码的格式错误,返回至输入项——>>>")
#print(str[0])
newnumber = change(str)
endnumber = change(str1)
end = dict()
for i in range(0,hang):
    for j in range(0,lie):
        end[endnumber[i][j]]=(i,j)
m=h(newnumber,endnumber)
n=g(newnumber,endnumber)
open=[]
maind = A(newnumber, endnumber)
while(True):

    if(maind==True):
        break
    else:
        for i in range(0,len(open)):
            if (same(maind[0],open[i])):
                maind[4]=hang*lie*10
            if(same(maind[1],open[i])):
                maind[5]=hang*lie*10
            if(same(maind[2],open[i])):
                maind[6]=hang*lie*10
            if(same(maind[3],open[i])):
                maind[7]=hang*lie*10
    l1=maind[0]
    l2=maind[1]
    l3=maind[2]
    l4=maind[3]
    l1n=maind[4]
    l2n=maind[5]
    l3n=maind[6]
    l4n=maind[7]
    if (l1n <= l2n):
        if (l3n <= l4n):
            if (l1n <= l3n):
                print(l1)
                maind = A(l1, endnumber)
                open.append(l1)
                continue
            else:
                print(l3)
                maind = A(l3, endnumber)
                open.append(l3)
                continue
        else:
            if (l1n <= l4n):
                print(l1)
                maind = A(l1, endnumber)
                open.append(l1)
                continue
            else:
                print(l4)
                maind = A(l4, endnumber)
                open.append(l4)
                continue
    else:
        if (l3n <= l4n):
            if (l2n <= l3n):
                print(l2)
                maind = A(l2, endnumber)
                open.append(l2)
                continue
            else:
                print(l3)
                maind = A(l3, endnumber)
                open.append(l3)
                continue
        else:
            if (l2n <= l4n):
                print(l2)
                maind = A(l2, endnumber)
                open.append(l2)
                continue
            else:
                print(l4)
                maind = A(l4, endnumber)
                open.append(l4)
                continue

实验结果:

以上方例子运行代码,结果如下:

输入要变化的数码问题的顺序(数据自左到右,自上到下):2831647 5
输入变化后的数码问题的顺序(数据自左到右,自上到下):1238 4765
输入数码的行数:3
输入数码的列数:3
[['2' '8' '3']
 ['1' ' ' '4']
 ['7' '6' '5']]
[['2' ' ' '3']
 ['1' '8' '4']
 ['7' '6' '5']]
[[' ' '2' '3']
 ['1' '8' '4']
 ['7' '6' '5']]
[['1' '2' '3']
 [' ' '8' '4']
 ['7' '6' '5']]
[['1' '2' '3']
 ['8' ' ' '4']
 ['7' '6' '5']]

以上是关于A*算法求解N数码的主要内容,如果未能解决你的问题,请参考以下文章

N数码问题的启发式搜索算法--A*算法python实现

八数码问题的问题,有解条件以及求解算法(宽度优先搜索)

A*算法求解八数码难题(python实现)

怎么样判断一个八数码问题有解还是无解啊?

八数码问题算法,谁有?

算法中搜索的艺术