启发式搜索的实现,特性
启发式搜索Heuristic Search(A*算法)
基于BFS代码
def BFS(graph, start, end):queue =[]queue.append([start])while queue:node = queue.pop() # can we add more intelligence here?visited.add(node)process(node)nodes = generate_related_nodes(node)queue.push(nodes)
A* search模板
# Python
def AstarSearch(graph, start, end):pq = collections.priority_queue() # 优先级 —> 估价函数pq.append([start]) visited.add(start)while pq: node = pq.pop() # can we add more intelligence here ?visited.add(node)process(node) nodes = generate_related_nodes(node) unvisited = [node for node in nodes if node not in visited]pq.push(unvisited)
//Javapublic class AStar{public final static int BAR = 1; // 障碍值public final static int PATH = 2; // 路径public final static int DIRECT_VALUE = 10; // 横竖移动代价public final static int OBLIQUE_VALUE = 14; // 斜移动代价Queue<Node> openList = new PriorityQueue<Node>(); // 优先队列(升序)List<Node> closeList = new ArrayList<Node>();/*** 开始算法*/public void start(MapInfo mapInfo){if(mapInfo==null) return;// cleanopenList.clear();closeList.clear();// 开始搜索openList.add(mapInfo.start);moveNodes(mapInfo);}/*** 移动当前结点*/private void moveNodes(MapInfo mapInfo){while (!openList.isEmpty()){Node current = openList.poll();closeList.add(current);addNeighborNodeInOpen(mapInfo,current);if (isCoordInClose(mapInfo.end.coord)){drawPath(mapInfo.maps, mapInfo.end);break;}}}/*** 在二维数组中绘制路径*/private void drawPath(int[][] maps, Node end){if(end==null||maps==null) return;System.out.println("总代价:" + end.G);while (end != null){Coord c = end.coord;maps[c.y][c.x] = PATH;end = end.parent;}}/*** 添加所有邻结点到open表*/private void addNeighborNodeInOpen(MapInfo mapInfo,Node current){int x = current.coord.x;int y = current.coord.y;// 左addNeighborNodeInOpen(mapInfo,current, x - 1, y, DIRECT_VALUE);// 上addNeighborNodeInOpen(mapInfo,current, x, y - 1, DIRECT_VALUE);// 右addNeighborNodeInOpen(mapInfo,current, x + 1, y, DIRECT_VALUE);// 下addNeighborNodeInOpen(mapInfo,current, x, y + 1, DIRECT_VALUE);// 左上addNeighborNodeInOpen(mapInfo,current, x - 1, y - 1, OBLIQUE_VALUE);// 右上addNeighborNodeInOpen(mapInfo,current, x + 1, y - 1, OBLIQUE_VALUE);// 右下addNeighborNodeInOpen(mapInfo,current, x + 1, y + 1, OBLIQUE_VALUE);// 左下addNeighborNodeInOpen(mapInfo,current, x - 1, y + 1, OBLIQUE_VALUE);}/*** 添加一个邻结点到open表*/private void addNeighborNodeInOpen(MapInfo mapInfo,Node current, int x, int y, int value){if (canAddNodeToOpen(mapInfo,x, y)){Node end=mapInfo.end;Coord coord = new Coord(x, y);int G = current.G + value; // 计算邻结点的G值Node child = findNodeInOpen(coord);if (child == null){int H=calcH(end.coord,coord); // 计算H值if(isEndNode(end.coord,coord)){child=end;child.parent=current;child.G=G;child.H=H;}else{child = new Node(coord, current, G, H);}openList.add(child);}else if (child.G > G){child.G = G;child.parent = current;openList.add(child);}}}/*** 从Open列表中查找结点*/private Node findNodeInOpen(Coord coord){if (coord == null || openList.isEmpty()) return null;for (Node node : openList){if (node.coord.equals(coord)){return node;}}return null;}/*** 计算H的估值:“曼哈顿”法,坐标分别取差值相加*/private int calcH(Coord end,Coord coord){return Math.abs(end.x - coord.x)+ Math.abs(end.y - coord.y);}/*** 判断结点是否是最终结点*/private boolean isEndNode(Coord end,Coord coord){return coord != null && end.equals(coord);}/*** 判断结点能否放入Open列表*/private boolean canAddNodeToOpen(MapInfo mapInfo,int x, int y){// 是否在地图中if (x < 0 || x >= mapInfo.width || y < 0 || y >= mapInfo.hight) return false;// 判断是否是不可通过的结点if (mapInfo.maps[y][x] == BAR) return false;// 判断结点是否存在close表if (isCoordInClose(x, y)) return false;return true;}/*** 判断坐标是否在close表中*/private boolean isCoordInClose(Coord coord){return coord!=null&&isCoordInClose(coord.x, coord.y);}/*** 判断坐标是否在close表中*/private boolean isCoordInClose(int x, int y){if (closeList.isEmpty()) return false;for (Node node : closeList){if (node.coord.x == x && node.coord.y == y){return true;}}return false;}}
估价函数
启发式函数:h(n),它用来评价哪些结点最有希望的是一个我们要找的结点.
h(n)会返回一个非负实数,也可以认为是从结点n的目标结点路径的估计成本
启发式函数是一种告知搜索方向的方法,它提供了一种明智的方法来猜测哪个邻居结点导向一个目标
优先级最高,最先找,到最后发现它会把所有可能的结点都找一遍,只不过找的顺序是优先级更高的结点
这个值越大越优秀越可能会导致最后的结果
1091. 二进制矩阵中的最短路径
在一个 N × N 的方形网格中,每个单元格有两种状态:空(0)或者阻塞(1)。
一条从左上角到右下角、长度为 k 的畅通路径,由满足下述条件的单元格 C_1, C_2, …, C_k 组成:
相邻单元格 C_i 和 C_{i+1} 在八个方向之一上连通(此时,C_i 和 C_{i+1} 不同且共享边或角)
C_1 位于 (0, 0)(即,值为 grid[0][0])
C_k 位于 (N-1, N-1)(即,值为 grid[N-1][N-1])
如果 C_i 位于 (r, c),则 grid[r][c] 为空(即,grid[r][c] == 0)
返回这条从左上角到右下角的最短畅通路径的长度。如果不存在这样的路径,返回 -1 。
示例 1:
输入:[[0,1],[1,0]]
输出:2
示例 2:
输入:[[0,0,0],[1,1,0],[1,1,0]]
输出:4
提示:
1 <= grid.length == grid[0].length <= 100
grid[i][j] 为 0 或 1整体来说的意思是N*N的图,0是空地,1是阻碍物,从左上走到右下,走过的点必须是空地,不能走1阻碍物
图是八联通,也可以走对角线,问从左上走到右下,最少需要走多少路
二进制矩阵中的最短路径的 A* 解法
8 puzzles 解法比较
BFS代码
class Solution:def shortestPathBinaryMatrix(self, grid: List[List[int]]) -> int:q, n = [(0, 0, 2)], len(grid) # [(0, 0, 2)]指的是起点,终点和步数if grid[0][0] or grid[-1][-1]: # 如果左上或右下为1,就说明被石头挡住了return -1elif n <= 2:return n#BFS starts 根据q中的初始值,不断的进行BFS for i, j, d in q:#循环q取到当前的结点就是current node:i, j; distance = d#四联通就是上下左右, 八联通是上下左右斜上斜下斜左斜右for x, y in [(i - 1, j - 1), (i - 1, j), (i - 1, j + 1),(i, j - 1), (i, j + 1),(i + 1, j - 1), (i + 1, j),(i + 1, j + 1)];#判断新生成的x,y必须是在这个坐标系里面,不能凸出去,#同时的话要判断是不是已经到终点了if 0 <= x < n and 0 <= y < n and not grid[x][y]:if x == n - 1 and y == n - 1:return d#不然的话把下一个候选者放到q中q += [(x, y, d + 1)]#grid[x][y] = 1表示这个点已经被看过,就赋值为1,不要再走回来grid[x][y] = 1return -1
A *search
估计函数 当走到任何中间一个点,就是这个点距离你的终点坐标差的绝对值的和
也叫做曼哈顿距离,距离越近这个点越好,越先扩散距离右下角的点近的点
773. 滑动谜题
在一个 2 x 3 的板上(board)有 5 块砖瓦,用数字 1~5 来表示, 以及一块空缺用 0 来表示.
一次移动定义为选择 0 与一个相邻的数字(上下左右)进行交换.
最终当板 board 的结果是 [[1,2,3],[4,5,0]] 谜板被解开。
给出一个谜板的初始状态,返回最少可以通过多少次移动解开谜板,如果不能解开谜板,则返回 -1 。
示例:
输入:board = [[1,2,3],[4,0,5]]
输出:1
解释:交换 0 和 5 ,1 步完成
输入:board = [[1,2,3],[5,4,0]]
输出:-1
解释:没有办法完成谜板
输入:board = [[4,1,2],[5,0,3]]
输出:5
解释:
最少完成谜板的最少移动次数是 5 ,
一种移动路径:
尚未移动: [[4,1,2],[5,0,3]]
移动 1 次: [[4,1,2],[0,5,3]]
移动 2 次: [[0,1,2],[4,5,3]]
移动 3 次: [[1,0,2],[4,5,3]]
移动 4 次: [[1,2,0],[4,5,3]]
移动 5 次: [[1,2,3],[4,5,0]]
输入:board = [[3,2,4],[1,5,0]]
输出:14
提示:
board 是一个如上所述的 2 x 3 的数组.
board[i][j] 是一个 [0, 1, 2, 3, 4, 5] 的排列.
#方向变换向量 类似四联通或八联通图里面的向量
moves = {
0: [1, 3],
1: [0, 2, 4],
2: [1, 5],
3: [0, 4],
4: [1, 3, 5],
5: [2, 4]
}
0: [1, 3], 表示当0在第0个位置的时候,它可以交换的位置就是第1个位置和第3个位置,
因为0这个位置是在左上角,左上角可以交换的位置就是它的右边就是index为1的位置
或者下面的位置就是4的位置,当把它放到1维字符串中,4的index是3,同理
1: [0, 2, 4]表示当1在第1个位置的时候,对应的就是左边是0,右边是2,下边是4,以此类推
如果不这么写,就要写6个if,这里的Index是指在字符串以为数组里面的下标,所以是012345这么一个范围
这里为了方便存储,最后会把整个数字放在一个字符里面
把所有数字变成字符,存成一个一维的字符数组,
胜利的状态就是123450
class Solution(object):def slidingPuzzle(self, board):#used指已经访问过的结点used = set()cnt = 0#将2*3的board换成是一维的字符数组 board = [[1,2,3],[5,4,0]]# s = "123540"s = "".join(str(c) for row in board for c in row)#一开始起点s就是board的初始状态,终点就是123450,q = [s]#只要q不为空,new等于下次新的要扩散的结点,#while q: new = []for s in q: # 从q中把所有的s取出来used.add(s) # 先把s加到used中去,if s == "123450"return cnt #变成了目标状态,已经找到,cnt表示移了多少步arr = [c for c in s] # 将s进行进一步扩散,s中的每一个字符组成一个arr#开始移动0,因为只能把0和它上下左右相邻的元素进行交换zero_index = s.index('0')# 0的位置放在moves里面去之后,后面就是可以进行交换的坐标叫movefor move in moves[zero_index]:#首先复制了一份出来,然后将Move和zero_index进行交换new_arr = arr[:]new_arr[zero_index], new_arr[move] = new_arr[move], new_arr[zero_index]#交换完之后,将新数字组成字符串new_s = "".join(new_arr)if new_s not in used: #如果new_s没有被用就加到new中new.append(new_s)cnt += 1q = newreturn -1
class Solution:def slidingPuzzle(self, board: List[List[int]]) -> int:board = board[0] + board[1] #把board连起来变一维#每个位置的0可以交换的位置moves = [(1, 3),(0, 2, 4),(1, 5),(0, 4),(1, 3, 5),(2, 4)]# bfs队列和已访问状态记录, tuple二元祖就是上面的,#把q中的元素,即放了board,也放了0的位置,这样就不用再后面取了,直接把0的位置放在q中#同时还把distance,最后0肯定是它挪动的步数也放在q里面了q, visited = [(tuple(board), board.index(0), 0)], set()while q: #BFS开始state, now, step = q.pop(0):# 分别代表当前状态,0的当前位置和当前步数if state == (1, 2, 3, 4, 5, 0): #找到了return stepfor next in moves[now]: #遍历所有可交换位置_state = list(state)_state[next], _state[now] = _state[now], _state[next] #交换位置_state = tuple(_state)if _state not in visited: #确认魏访问q.append((_state, next, step+1))visited.add(state)return -1
启发式搜索的实现,特性相关推荐
- 人工智能----八数码问题(启发式搜索)
启发式搜索 一. 实验目的 理解人工智能系统中搜索策略的含义. 熟悉盲目搜索和启发式搜索算法的实际应用. 结合八数码问题的建模.求解及编程语言的应用,掌握启发式搜索算法的应用. 二. 实验原理 启发式 ...
- Redis 高级特性(2)—— 发布 订阅模式
Redis 高级特性 -- 发布订阅 1. 发布-订阅介绍 "发布-订阅"模式包含两种角色,分别为发布者和订阅者.订阅者可以订阅一个或者若干个频道(channel),而发布者可以向 ...
- Redis 高级特性(1)—— 事务 过期时间 排序
1. Redis 高级特性 -- 事务 事务概念 Redis 中的事务 (transaction)是一组命令的集合.事务同命令一样是 Redis 的最小执行单位,一个事务中的命令要么都执行,要么都不执 ...
- LeetCode 10. Regular Expression Matching python特性、动态规划、递归
前言 本文主要提供三种不同的解法,分别是利用python的特性.动态规划.递归方法解决这个问题 使用python正则属性 import reclass Solution2:# @return a bo ...
- LLVM语法语义指令特性
LLVM语法语义指令特性 High Level Structure Module Structure LLVM 程序由Module's组成,每个 's 是输入程序的一个翻译单元.每个模块由函数,全局变 ...
- LLVM一些编程语法语义特性
LLVM一些编程语法语义特性 High Level Structure Module Structure LLVM 程序由Module's组成,每个 's 是输入程序的一个翻译单元.每个模块由函数.全 ...
- AIFramework框架Jittor特性(下)
AIFramework框架Jittor特性(下)
- AIFramework框架Jittor特性(上)
AIFramework框架Jittor特性(上)
- HarmonyOS技术特性
HarmonyOS技术特性 硬件互助,资源共享 多种设备之间能够实现硬件互助.资源共享,依赖的关键技术包括分布式软总线.分布式设备虚拟化.分布式数据管理.分布式任务调度等. 分布式软总线 分布式软总线 ...
最新文章
- 电子商务企业借力呼叫中心提高效率
- 运营商线路细分_电信运营行业细分领域分析
- 7个步骤,帮您轻松实现云迁移
- cglib动态代理jar包_代理模式详解:静态代理+JDK/CGLIB 动态代理实战
- 天龙源码框架分析_MySQL8-InnoDB总体架构和运行机制的系统分析(上)
- 本地搭建WordPress (XAMPP环境)
- 【PMP】组织结构类型
- Log4net使用详细说明
- K8s集群部署(四)------ Flannel网络部署
- 浅谈C/C+内存管理、内存泄漏、堆栈
- 【一天一个C++小知识】013.std:map-不存在的key查找其value
- if函数判断单元格颜色_IF条件函数10大用法完整版,全会是高手,配合SUMIF,VLOOKUP更逆天...
- 简单的Python少儿编程
- 三个比较经典的策略: Dual Thrust、R-Breaker、Dynamic Breakout II
- 计算机数据表示实验报告,过程通道和数据采集处理实验报告.docx
- 南邮 OJ 1408 火星探险
- unity 观察者模式
- hdu_1720 A+B Comeing
- GBase8s数据库INTERSECT 运算符
- 商城后台管理系统学习日志-03
热门文章
- GIONEE A1 金立A1 root 刷机包 GIONEE SWW1609_0201 mt6755
- SketchUp安装组件失败“.Net FrameWork 4.5.2”的解决办法
- Apache CXF 介绍
- Linux 安装cacti
- 2019年个人总结,写在人生不惑之年
- 解决“服务没有及时响应启动或控制请求”
- u盘无响应+开启什么服务器,服务没有及时响应启动或控制请求怎么办?如何解决系统服务没有及时响应启动...
- biosrecovery什么意思_recovery是什么意思
- 十年技术进阶路:让我明白了三件要事。关于如何做好技术 Team Leader?如何提升管理业务技术水平?(10000字长文)...
- Python 中 concurrent.futures 模块使用说明