启发式搜索

启发式搜索是一种对搜索到的每一个位置进行评估,然后从评估的最优位置进行搜索直到目的地,
由于搜索时对每一个位置的评估是基于直观或经验的所有叫启发式搜索

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函数会有不同的效果,但大致有两条规律:

  1. 如果h(x)>x到终点的实际代价,则可以尽快找到一个解,但不一定是最优解
  2. 如果$h(x)\le$x到终点的实际代价,则如果有解,一定是最优解
    且h(x)和x到终点的实际代价相差越大,搜到的无关节点越多

例题

luoguP1379 八数码难题

#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基本一样:

  1. 确定一个限制深度,然后进行DFS
  2. 如果在限制深度内得不到解就将限制深度加深,继续DFS
  3. 如果得到解就输出

只是在dfs的时候利用A*思想估计剩余深度,如果当前深度+估计值>限制深度就退出本次搜索

例题hdu1667 The Rotation Game

/******************************************************************
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*算法的更多相关文章

  1. 启发式搜索A*算法

    A* 寻路算法 (2011-02-15 10:53:11) 转载▼ 标签: 游戏 分类: 算法 概述 虽然掌握了 A* 算法的人认为它容易,但是对于初学者来说, A* 算法还是很复杂的. 搜索区域(T ...

  2. 启发式搜索A-Star算法 【寻找 最短路径 算法】【地理几何位置 可利用的情况】

    在处理最短路径问题时,有一种启发式算法是我们应该了解的,由于其有着优秀的探索效率在各自现实项目中多有应用,它就是 A-star 算法,或  A*  算法. 个人观点: A*  算法并不保证找到的路径一 ...

  3. 启发式搜索 A*算法的OC 实现

    前两天重新学习了下A*算法,上次学习A*算法已经是5年前了,看到网上铺天盖地的A*算法都是C.C++等等其他语言的,就是没有OC 的,所以抽空写了一份.今天太晚了就不说明A*算法的细节了,大家如果想学 ...

  4. A*搜寻算法(A星算法)

    A*搜寻算法[编辑] 维基百科,自由的百科全书 本条目需要补充更多来源.(2015年6月30日) 请协助添加多方面可靠来源以改善这篇条目,无法查证的内容可能会被提出异议而移除. A*搜索算法,俗称A星 ...

  5. 【算法入门】深度优先搜索(DFS)

    深度优先搜索(DFS) [算法入门] 1.前言深度优先搜索(缩写DFS)有点类似广度优先搜索,也是对一个连通图进行遍历的算法.它的思想是从一个顶点V0开始,沿着一条路一直走到底,如果发现不能到达目标解 ...

  6. 深度优先搜索(DFS)

    [算法入门] 郭志伟@SYSU:raphealguo(at)qq.com 2012/05/12 1.前言 深度优先搜索(缩写DFS)有点类似广度优先搜索,也是对一个连通图进行遍历的算法.它的思想是从一 ...

  7. POJ 2449 Remmarguts' Date --K短路

    题意就是要求第K短的路的长度(S->T). 对于K短路,朴素想法是bfs,使用优先队列从源点s进行bfs,当第K次遍历到T的时候,就是K短路的长度. 但是这种方法效率太低,会扩展出很多状态,所以 ...

  8. dfs介绍

    深度优先搜索(DFS) [算法入门] 郭志伟@SYSU:raphealguo(at)qq.com 2012/05/12 1.前言 深度优先搜索(缩写DFS)有点类似广度优先搜索,也是对一个连通图进行遍 ...

  9. 数据结构6——DFS

    一.相关定义 深度优先遍历,也有称为深度优先搜索,简称DFS.其实,就像是一棵树的前序遍历. 初始条件:图G所有顶点均未被访问过,任选一点v. 思想:是从一个顶点V1开始,沿着一条路一直走到底,如果发 ...

随机推荐

  1. vue-router配置子路由

    1.改写App.vue 里面的代码 ,增加路由跳转,增加Hi页面1,Hi页面2的跳转 2.修改HI.vue 里面的内容,增加 <router-view class="aaa" ...

  2. linux 下使用scp命令传输文件

    scp -P 1234 /home/wakasann/test.txt wakasann@192.168.1.30:/var/www/html/ 使用 1234端口,将 test.txt文件传输到服务 ...

  3. String--->Double 不依赖地域性的转换

    double.TryParse(icStr, System.Globalization.NumberStyles.Any, System.Globalization.CultureInfo.Invar ...

  4. leetcood学习笔记-79-单词搜索

    题目描述: 方法一;回溯 class Solution: def exist(self, board: List[List[str]], word: str) -> bool: max_x,ma ...

  5. C/C++ 公有函数无法返回私有的类对象解决方案

    { 能出这种错的说明还需要提升C++,增强对类的理解 解决方案:把你的私有的对象的私有的拷贝构造或者同类赋值改为公开的 }

  6. SpringBoot使用拦截器/ Servlet/ Filter

    一.SpringBoot中使用拦截器 使用SpringMVC的拦截器,需要定义好拦截器,然后通过配置文件文件,对其进行注册 而在SpringBoot项目中,之前在配置文件中配置的内容,现在体现在一个类 ...

  7. x-杂项-maven-repository-lombok-intro:使用PROJECT LOMBOK减少BOILERPLATE代码

    ylbtech-杂项-maven-repository-lombok-intro:使用PROJECT LOMBOK减少BOILERPLATE代码 1.返回顶部 1. REDUCING BOILERPL ...

  8. ArrayList 和linkedList 插入比较

    从学Java开始, 就一直大脑记着  arrayList 底层是数组 ,查询快, 插入慢, 有移动的动作.linkedList 底层链表, 插入快 查询慢,今天写了例子跑了跑, 果然. public ...

  9. python调用scikit-learn机器学习

    不支持深度学习和强化学习 numpy介绍: np.eye(n)生成一个n维单元数组 数据预处理: iris数据加载 from sklearn import datasetsiris = dataset ...

  10. 基于Java Properties类设置本地配置文件

    一.Java Properties类介绍 Java中有个比较重要的类Properties(Java.util.Properties),主要用于读取Java的配置文件,各种语言都有自己所支持的配置文件, ...