• 一、启发式搜索:A算法

1)评价函数的一般形式 : f(n) = g(n) + h(n)

g(n):从S0到Sn的实际代价(搜索的横向因子)

h(n):从N到目标节点的估计代价,称为启发函数(搜索的纵向因子);

特点: 效率高, 无回溯,

搜索算法

OPEN表 : 存放待扩展的节点.

CLOSED表 : 存放已被扩展过的节点.

2)评价函数  f(x) = g(x) + h(x)

当f(x) = g(x)   时,为宽度优先搜索

当f(x) = 1/g(x)时,为深度优先搜索

当f(x) = h(x)   时,为全局优先搜索

比较f(x)大小,决定节点搜索顺序,即在OPEN表中的顺序

3)Step1:   把初始节点S0放入OPEN表中;

Step2:   若OPEN表为空,则搜索失败,退出.

Step3:   移出OPEN中第一个节点N放入CLOSED表中, 并标以顺序号n;

Step4:   若目标节点Sg=N, 则搜索成功,结束.

Step5:   若N不可扩展, 则转Step2;

Step6:   扩展N, 生成一组子节点, 对这组子节点作如下处理后, 放入  OPEN表, 按f值重新排序OPEN表, 转 Step2;

删除重复节点和修改返回指针处理.

  • 二、启发式搜索:A*算法

1)评价函数的一般形式:

f(n) = g(n) + h(n)  且  h(n) <= h*(n)

g(n),h(n):定义同A算法;

h*(n):从N到目标节点的最短路径; 称此时的A算法为A*算法.

2)程序关键点

节点的扩展:close表存放已经扩展后的状态,open表存放未扩展的状态。首先获取节点能扩展的方向,扩展后将父节点放入close表中,如果转移之后的节点,既不在close表也不再open表,表明该节点还未被扩展,则插入open表,如果在close表中表明之前已经扩展过该状态,为了避免无限扩展应将该状态从open表舍弃,如果在open表则比较这两个矩阵的f值(选取最优解),留小的在open表,之后对open表中的节点根据f值进行排序,pop出f值最小的节点进行扩展,依次进行该过程,直至该节点为目标状态。
解的路径的输出:通过目标状态节点向上回溯找其父节点,直至开始状态。
  • 三、python代码实现
 # -*- coding: utf-8 -*-
"""
Created on Sun Sep 16 14:31:40 2018
A*算法解决N数码问题
运行程序后如下是输入格式:
请输入矩阵的行数 3 输入对应的N
请输入初始矩阵A 1 0 2 一行行输入,每行数字空格隔开,每行最后一个数字输入完成后直接回车开始输入第二行 4 5 6 3 7 8
请输入目标矩阵B 1 2 3 8 0 4 7 6 5 """
import numpy as np
import copy
import time
from operator import itemgetter goal = {} def get_location(vec, num): #根据num元素获取num在矩阵中的位置
row_num = vec.shape[0] #numpy-shape函数获得矩阵的维数
line_num = vec.shape[1] for i in range(row_num):
for j in range(line_num):
if num == vec[i][j]:
return i, j def get_actions(vec): #获取当前位置可以移动的下一个位置,返回移动列表
row_num = vec.shape[0]
line_num = vec.shape[1] (x, y) = get_location(vec, 0) #获取0元素的位置
action = [(0, 1), (0, -1), (1, 0), (-1, 0)] if x == 0: #如果0在边缘则依据位置情况,减少0的可移动位置
action.remove((-1, 0))
if y == 0:
action.remove((0, -1))
if x == row_num - 1:
action.remove((1, 0))
if y == line_num - 1:
action.remove((0, 1)) return list(action) def result(vec, action): #移动元素,进行矩阵转化
(x, y) = get_location(vec, 0) #获取0元素的位置
(a, b) = action #获取可移动位置 n = vec[x+a][y+b] #位置移动,交换元素
s = copy.deepcopy(vec)
s[x+a][y+b] = 0
s[x][y] = n return s def get_ManhattanDis(vec1, vec2): #计算两个矩阵的曼哈顿距离,vec1为目标矩阵,vec2为当前矩阵
row_num = vec1.shape[0]
line_num = vec1.shape[1]
dis = 0 for i in range(row_num):
for j in range(line_num):
if vec1[i][j] != vec2[i][j] and vec2[i][j] != 0:
k, m = get_location(vec1, vec2[i][j])
d = abs(i - k) + abs(j - m)
dis += d return dis def expand(p, actions, step): #actions为当前矩阵的可扩展状态列表,p为当前矩阵,step为已走的步数
children = [] #children用来保存当前状态的扩展节点
for action in actions:
child = {}
child['parent'] = p
child['vec'] = (result(p['vec'], action))
child['dis'] = get_ManhattanDis(goal['vec'], child['vec'])
child['step'] = step + 1 #每扩展一次当前已走距离加1
child['dis'] = child['dis'] + child['step'] #更新该节点的f值 f=g+h(step+child[dis])
child['action'] = get_actions(child['vec'])
children.append(child) return children def node_sort(nodelist): #按照节点中字典的距离字段对列表进行排序,从大到小
return sorted(nodelist, key = itemgetter('dis'), reverse=True) def get_input(num):
A = []
for i in range(num):
temp = []
p = []
s = input()
temp = s.split(' ')
for t in temp:
t = int(t)
p.append(t)
A.append(p) return A def get_parent(node):
q = {}
q = node['parent']
return q def test():
openlist = [] #open表
close = [] #存储扩展的父节点 print('请输入矩阵的行数')
num = int(input()) print("请输入初始矩阵A")
A = get_input(num) print("请输入目标矩阵B")
B = get_input(num) print("请输入结果文件名")
resultfile = input() goal['vec'] = np.array(B) #建立矩阵 p = {}
p['vec'] = np.array(A)
p['dis'] = get_ManhattanDis(goal['vec'], p['vec'])
p['step'] = 0
p['action'] = get_actions(p['vec'])
p['parent'] = {} if (p['vec'] == goal['vec']).all():
return openlist.append(p) start_CPU = time.clock() #开始扩展时CPU开始计算 while openlist: children = [] node = openlist.pop() #node为字典类型,pop出open表的最后一个元素
close.append(node) #将该元素放入close表 if (node['vec'] == goal['vec']).all(): #比较当前矩阵和目标矩阵是否相同
end_CPU = time.clock() #CPU结束计算 h = open(resultfile,'w',encoding='utf-8',) #将结果写入文件 并在控制台输出
h.write('搜索树规模:' + str(len(openlist)+len(close)) + '\n')
h.write('close:' + str(len(close)) + '\n')
h.write('openlist:' + str(len(openlist)) + '\n')
h.write('cpu运行时间:' + str(end_CPU - start_CPU) + '\n')
h.write('路径长:' + str(node['dis']) + '\n') h.write('解的路径:' + '\n')
i = 0
way = []
while close:
way.append(node['vec']) #从最终状态开始依次向上回溯将其父节点存入way列表中
node = get_parent(node)
if(node['vec'] == p['vec']).all():
way.append(node['vec'])
break
while way:
i += 1
h.write(str(i) + '\n')
h.write(str(way.pop()) + '\n')
h.close()
f = open(resultfile,'r',encoding='utf-8',)
print(f.read()) return children = expand(node, node['action'], node['step']) #如果不是目标矩阵,对当前节点进行扩展,取矩阵的可能转移情况 for child in children: #如果转移之后的节点,既不在close表也不再open表则插入open表,如果在close表中则舍弃,如果在open表则比较这两个矩阵的f值,留小的在open表
f = False
flag = False
j = 0
for i in range(len(openlist)):
if (child['vec'] == openlist[i]['vec']).all():
j = i
flag = True
break
for i in range(len(close)):
if(child['vec'] == close[i]).all():
f = True
break
if f == False and flag == False :
openlist.append(child) elif flag == True:
if child['dis'] < openlist[j]['dis']:
del openlist[j]
openlist.append(child) openlist = node_sort(openlist) #对open表进行从大到小排序 test()
  • 四、程序运行结果如下图所示

图 1

 

图 2

图 3

  • 五、总结

通过这次编程了解到了搜索具有探索性,要提高搜索效率(尽快地找到目标节点),或要找最佳路径(最佳解)就必须注意搜索策略。对于状态图搜索,已经提出了许多策略,它们大体可分为盲目搜索(bland search)和启发式搜索(heuristic search)两大类。其中盲目搜索是无向导搜索。启发式搜索是有向导搜索,即利用启发信息(函数)引导去寻找问题解。通过A*算法解决N数码问题实验过程中也遇到很多问题,比如节点扩展的方向问题等,通过这次实验不仅锻炼了自己python编程能力,也让自己对N数码求解最优路径问题有了更清晰的认识,希望自己能在老师和同学的帮助下,能不断进步,当然最重要的是自己得付出,只会幻想而不行动的人,永远也体会不到收获果实时的喜悦。加油!!

N数码问题的启发式搜索算法--A*算法python实现的更多相关文章

  1. 【小白学游戏常用算法】二、A*启发式搜索算法

    在上一篇博客中,我们一起学习了随机迷宫算法,在本篇博客中,我们将一起了解一下寻路算法中常用的A*算法. 通常情况下,迷宫寻路算法可以使用深度优先或者广度优先算法,但是由于效率的原因,不会直接使用这些算 ...

  2. pageRank算法 python实现

    一.什么是pagerank PageRank的Page可是认为是网页,表示网页排名,也可以认为是Larry Page(google 产品经理),因为他是这个算法的发明者之一,还是google CEO( ...

  3. 常见排序算法-Python实现

    常见排序算法-Python实现 python 排序 算法 1.二分法     python    32行 right = length-  :  ]   ):  test_list = [,,,,,, ...

  4. kmp算法python实现

    kmp算法python实现 kmp算法 kmp算法用于字符串的模式匹配,也就是找到模式字符串在目标字符串的第一次出现的位置比如abababc那么bab在其位置1处,bc在其位置5处我们首先想到的最简单 ...

  5. KMP算法-Python版

                               KMP算法-Python版 传统法: 从左到右一个个匹配,如果这个过程中有某个字符不匹配,就跳回去,将模式串向右移动一位.这有什么难的? 我们可以 ...

  6. 压缩感知重构算法之IRLS算法python实现

    压缩感知重构算法之OMP算法python实现 压缩感知重构算法之CoSaMP算法python实现 压缩感知重构算法之SP算法python实现 压缩感知重构算法之IHT算法python实现 压缩感知重构 ...

  7. 压缩感知重构算法之OLS算法python实现

    压缩感知重构算法之OMP算法python实现 压缩感知重构算法之CoSaMP算法python实现 压缩感知重构算法之SP算法python实现 压缩感知重构算法之IHT算法python实现 压缩感知重构 ...

  8. 压缩感知重构算法之CoSaMP算法python实现

    压缩感知重构算法之OMP算法python实现 压缩感知重构算法之CoSaMP算法python实现 压缩感知重构算法之SP算法python实现 压缩感知重构算法之IHT算法python实现 压缩感知重构 ...

  9. 压缩感知重构算法之IHT算法python实现

    压缩感知重构算法之OMP算法python实现 压缩感知重构算法之CoSaMP算法python实现 压缩感知重构算法之SP算法python实现 压缩感知重构算法之IHT算法python实现 压缩感知重构 ...

随机推荐

  1. 查看 Android App 的 versionCode

    有 App 源码时,可以直接查看 AndroidManifest.xml 文件. <manifest android:versionName="1.4" android:ve ...

  2. c# ado.net eftity framework 返回多表查询结果

    public static IQueryable GetWeiXinTuWenList() { using (var Model = new Model.WeiXinEntities()) { var ...

  3. vue-router 嵌套路由没反应

    先看下route.js //route.js const App = () => import('../App.vue'); const Login = () => import('../ ...

  4. Nginx服务器部署SSL证书手机不信任解决方法

    在wosign申请证书并按指南正确部署证书后,如果发现PC浏览器访问正常,手机或safari浏览器提示证书不受信任,那肯定是在文件传输解压过程中导致证书文件中出现空格.乱码之类的情况,这里教您轻松四步 ...

  5. [luogu4159 SCOI2009] 迷路(矩阵乘法)

    传送门 Solution 矩阵乘法新姿势qwq 我们知道当边权为1是我们可以利用矩阵快速幂来方便的求出路径数 那么对于边权很小的时候,我们可以将每个点都拆成若干个点 然后就将边权不为1转化为边权为1了 ...

  6. NLTK学习笔记(二):文本、语料资源和WordNet汇总

    目录 语料库基本函数表 文本语料库分类 常见语料库及其用法 载入自定义语料库 词典资源 停用词语料库 WordNet面向语义的英语字典 语义相似度 语料库基本函数表 示例 描述 fileids() 语 ...

  7. 第三次训练 密码acmore

    网站:CSUST7月23号 A题:大意是:一个N多边形,用红,绿,蓝三色给定点上色,要求划分成顶点颜色不同的三角形. 解析: 这道题是黑书上分治法的例题,还是比较巧的. 首先很容易发现当某种颜色的点只 ...

  8. Spring MVC-表单(Form)处理示例(转载实践)

    以下内容翻译自:https://www.tutorialspoint.com/springmvc/springmvc_form_handling.htm 说明:示例基于Spring MVC 4.1.6 ...

  9. sublime text 插件emmet快捷命令

    原文链接:http://www.17yaobai.com/?p=255 语法: 后代:> 缩写:nav>ul>li <nav> <ul> <li> ...

  10. svn 插件安装

    方法一:link安装  1.从官网下载site-1.6.18.zip文件. 2.从中解压出features与 plugins目录.拷贝到D:\MyEclipse\myPlugin\svn里面,其他的* ...