启发式搜索——A*算法
启发式搜索
启发式搜索是一种对搜索到的每一个位置进行评估,然后从评估的最优位置进行搜索直到目的地,
由于搜索时对每一个位置的评估是基于直观或经验的所有叫启发式搜索
A*算法
历史:
1964年Nils Nilsson提出了A1算法,是一个启发式搜索算法,
而后又被改进成为A2算法,直到1968年,被Peter E. Hart改进成为A*算法
主要思想:
1.对于每个搜索到的点求一个估价函数f(x)。
$\large f(x)=g(x)+h(x)$
其中g(x)表示起点到当前点实际走的代价,h(x)表示当前点x到终点的估算代价。
2.并将这个搜索到的点按f(x)加入一个待搜索列表中。
3.每次从待搜索列表取出f(x)最小的点加入搜索过列表,并从这个点开始进行搜索
4.重复1。
注意:如果搜索到的一个点已经在待搜索列表(在搜索过列表不算)中
则要更新它的f值,而不是什么也不做,因为可能出现下面这种情况

红色为起点,绿色为终点,灰色为搜索过列表中的点,黄色为待搜索列表中的点,蓝色的是障碍。
如果按和终点的曼哈顿距离算h(x)则会搜索成这种情况,
这时被圈出的黄色的点g(x)=被圈出的灰色的点的g(x)+1。
这显然不是最优的g值
所以搜索时在遇到待搜索列表中的点要更新它的f值
h函数的选择
由于h函数只是一个估计值,所以对于每个题目可以有许多h函数的选择方法
选择不同的h函数会有不同的效果,但大致有两条规律:
- 如果h(x)>x到终点的实际代价,则可以尽快找到一个解,但不一定是最优解
- 如果$h(x)\le$x到终点的实际代价,则如果有解,一定是最优解
且h(x)和x到终点的实际代价相差越大,搜到的无关节点越多
例题
#include<cstdio>
#include<cmath>
#include<algorithm>
#include<queue>
#include<cstring>
using namespace std;
const int fac[]={, , , , , , , , };
int cantor(int a[],int k){//康托展开
int ans=,tmp;
for(int i=;i<k;i++){
tmp=;
for(int j=i+;j<k;j++){
if(a[i]>a[j])tmp++;
}
ans+=tmp*fac[k-i-];
}
return ans;
}
void uncantor(int a[],int k,int num){//逆康托展开
int b[];
for(int i=;i<k;i++)b[i]=i+;
b[k]=;
for(int i=,x;i<k;i++){
x=num/fac[k-i-],num%=fac[k--i];
a[i]=b[x]-;
for(int j=x;b[j];j++)b[j]=b[j+];
}
}
int ma,dis[][],go[][]={{,},{-,},{,},{,-}},a[],b[];
bool vis[];
int h(){//估价代价
int ans=;
for(int i=,j;i<;i++){
for(j=;j<;j++){
if(a[i]==b[j])break;
}
if(a[i])ans+=dis[i][j];
}
return ans;
}
struct Node{
int x,f,g;//x为状态的康托展开值,
bool operator < (const Node &b)const{
return f>b.f;
}
}node,w;
priority_queue<Node> q;
int astr(int now,int t){//A*算法
node.x=now;
node.f=h();
node.g=;
q.push(node);
while(!q.empty()){
w=q.top(),q.pop();
if(vis[w.x])continue;
vis[w.x]=;
if(w.x==t){
return w.f;
}
uncantor(a,,w.x);
int x,y;
for(int i=;i<;i++){
if(a[i]==){
x=i/,y=i%;break;
}
}
for(int i=;i<;i++){
int x1=x+go[i][],y1=y+go[i][];
if(x1>=&&x1<&&y1>=&&y1<){
swap(a[x1*+y1],a[x*+y]);
node.x=cantor(a,),node.g=w.g+,node.f=h()+node.g;
if(!vis[node.x])q.push(node);
swap(a[x1*+y1],a[x*+y]);
}
}
}
return ;
}
int main(){
char s[];int st,t;
sscanf("","%s",s);
for(int i=;i<;i++)b[i]=s[i]^0x30;
t=cantor(b,);
scanf("%s",s);
for(int i=;i<;i++)a[i]=s[i]^0x30;
st=cantor(a,);
vis[st]=;
for(int i=;i<;i++){
for(int j=i+;j<;j++){
dis[j][i]=dis[i][j]=j/-i/+abs(i%-j%);
}
}
memset(vis,,sizeof(vis));
printf("%d",astr(st,t));
return ;
}
IDA*
A*算法和bfs一样都要记录每个节点是否被访问过了,有些题目的状态不好表示
使用A*算法就会非常麻烦,这时就可以使用IDDFS的A*思想优化版IDA*(IDA*并不是迭代加深A*)
具体操作
具体操作和IDDFS基本一样:
- 确定一个限制深度,然后进行DFS
- 如果在限制深度内得不到解就将限制深度加深,继续DFS
- 如果得到解就输出
只是在dfs的时候利用A*思想估计剩余深度,如果当前深度+估计值>限制深度就退出本次搜索
/******************************************************************
IDA*
******************************************************************/
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int center[] = {,,,,,,,}; //中心8个点的位置
const int reversetp[] = {,,,,,,,}; //每种操作的逆操作
const int op[][] = { //从A-H操作的值的下标
{ , , ,,,, }, //A
{ , , ,,,, }, //B
{ , , , , , , }, //C
{ ,,,,,, }, //D
{ ,,,, , , }, //E
{ ,,,, , , }, //F
{ ,,,,,, }, //G
{ , , , , , , }, //H
};
int a[];
int h(){
int num[]={};
for(int i=;i<;i++){
num[a[center[i]]-]++;
}
return -max(num[],max(num[],num[]));
}
bool f;char ans[];
void modify(int x){
int w=a[op[x][]];
for(int i=;i<;i++)a[op[x][i]]=a[op[x][i+]];
a[op[x][]]=w;
}
void idastar(int d,int maxd){
if(f)return;
if(d==maxd){
if(!h())f=,ans[d]=,printf("%s\n%d\n",ans,a[]);
return;
}
if(d>maxd||d+h()>maxd)return;
for(int i=;i<;i++){
modify(i);
ans[d]=(i^0x40)+,idastar(d+,maxd);
modify(reversetp[i]);
}
}
void work(){
for(int i=;i<;i++)scanf("%d",a+i);
if(!h()){
printf("No moves needed\n%d\n",a[]);
return;
}
f=;
for(int i=;;i++){
idastar(,i);
if(f)return;
}
}
int main(){
while(~scanf("%d",a)&&a[])work();
return ;
}
启发式搜索——A*算法的更多相关文章
- 启发式搜索A*算法
A* 寻路算法 (2011-02-15 10:53:11) 转载▼ 标签: 游戏 分类: 算法 概述 虽然掌握了 A* 算法的人认为它容易,但是对于初学者来说, A* 算法还是很复杂的. 搜索区域(T ...
- 启发式搜索A-Star算法 【寻找 最短路径 算法】【地理几何位置 可利用的情况】
在处理最短路径问题时,有一种启发式算法是我们应该了解的,由于其有着优秀的探索效率在各自现实项目中多有应用,它就是 A-star 算法,或 A* 算法. 个人观点: A* 算法并不保证找到的路径一 ...
- 启发式搜索 A*算法的OC 实现
前两天重新学习了下A*算法,上次学习A*算法已经是5年前了,看到网上铺天盖地的A*算法都是C.C++等等其他语言的,就是没有OC 的,所以抽空写了一份.今天太晚了就不说明A*算法的细节了,大家如果想学 ...
- A*搜寻算法(A星算法)
A*搜寻算法[编辑] 维基百科,自由的百科全书 本条目需要补充更多来源.(2015年6月30日) 请协助添加多方面可靠来源以改善这篇条目,无法查证的内容可能会被提出异议而移除. A*搜索算法,俗称A星 ...
- 【算法入门】深度优先搜索(DFS)
深度优先搜索(DFS) [算法入门] 1.前言深度优先搜索(缩写DFS)有点类似广度优先搜索,也是对一个连通图进行遍历的算法.它的思想是从一个顶点V0开始,沿着一条路一直走到底,如果发现不能到达目标解 ...
- 深度优先搜索(DFS)
[算法入门] 郭志伟@SYSU:raphealguo(at)qq.com 2012/05/12 1.前言 深度优先搜索(缩写DFS)有点类似广度优先搜索,也是对一个连通图进行遍历的算法.它的思想是从一 ...
- POJ 2449 Remmarguts' Date --K短路
题意就是要求第K短的路的长度(S->T). 对于K短路,朴素想法是bfs,使用优先队列从源点s进行bfs,当第K次遍历到T的时候,就是K短路的长度. 但是这种方法效率太低,会扩展出很多状态,所以 ...
- dfs介绍
深度优先搜索(DFS) [算法入门] 郭志伟@SYSU:raphealguo(at)qq.com 2012/05/12 1.前言 深度优先搜索(缩写DFS)有点类似广度优先搜索,也是对一个连通图进行遍 ...
- 数据结构6——DFS
一.相关定义 深度优先遍历,也有称为深度优先搜索,简称DFS.其实,就像是一棵树的前序遍历. 初始条件:图G所有顶点均未被访问过,任选一点v. 思想:是从一个顶点V1开始,沿着一条路一直走到底,如果发 ...
随机推荐
- C++ 系列:函数可变长参数
一.基础部分 1.1 什么是可变长参数 可变长参数:顾名思义,就是函数的参数长度(数量)是可变的.比如 C 语言的 printf 系列的(格式化输入输出等)函数,都是参数可变的.下面是 printf ...
- ransformResourcesWithMergeJavaResForDebug问题
错误内容: Error:Execution failed for task ':app:transformResourcesWithMergeJavaResForDebug'. > java.i ...
- How to Hide Apache Tomcat Version Number from Error Pages
1. 进入tomcat lib目录 cd /usr/local/tomcat7/lib 2. 解压catalina.jar jar xvf catalina.jar 3. 修改ServerInfo.p ...
- ideal的maven项目不小心remove module,如何找回
找回方式: ideal的最右侧有个maven projects 点开后点击“+”,也就是Add Maven Projects,寻找不小心remove modules 的 子项目的pom文件所在的位置, ...
- 根据Cron表达式,通过Spring自带的CronSequenceGenerator类获取下次执行时间
Cron表达式通常用于执行一些定时任务,在本篇文章中,暂时不会记录如何根据Cron表达式来执行一些定时任务.本章主要的目的是根据Cron表达式,通过Spring自带的CronSequenceGener ...
- requests 返回 521
网页端抓数据免不了要跟JavaScript打交道,尤其是JS代码有混淆,对cookie做了手脚.找到cookie生成的地方要费一点时间. 那天碰到这样一个网页,用浏览器打开很正常.然而用request ...
- 4_1.springboot2.xWeb开发使用thymeleaf
1.简介 如果使用SpringBoot: 1).创建SpringBoot应用,选中我们需要的模块: 2).SpringBoot已经默认将这些场景配置好了,只需要在配置文件中指定少量配置就可以运行起来: ...
- 初识OpenCV-Python - 009: 图像梯度
本节学习找到图像的梯度和边界.只要用到的函数为: cv2.Sobel(), cv2.Scharr(), cv2.Laplacian() 1. Laplacian 和 Sobel的对比 import c ...
- appium基础一:连接手机和appium-desktop定位元素
一.获取手机信息 adb devices获取手机或模拟器的设备名 aapt dump badging xxxx.apk获取app的包名.入口等基本信息 如果想要知道手机原生携带的app的基本信息,首先 ...
- 【LGP5349】幂
题目 比较厉害的题目了 求 \[\sum_{i=0}^{\infty}\sum_{j=0}^nf_ji^jr^i\] 改变一下求和顺序 \[\sum_{j=0}f_j\sum_{i=0}^{\inft ...