A star


          A star Algorithms

A* 算法的使用重点在于一个估值函数f的设计:

f = g + h 

g = 从起点A,沿着产生的路径,移动到网格上指定方格的移动耗费。 

h = 从网格上那个方格移动到终点B的预估移动耗费。

A*算法之所以称之为Heuristic Search,不同于DFS(Depth First Search),BSF(Breadth First Search),它使用了h这个启发式函数。h函数经常被称为启发式的,主要的原因是因为它只是个猜测。我们没办法事先知道路径的长度,因为路上可能存在各种障碍(墙,水,等等)。 

一种具有f=g+h策略的启发式算法能成为A*算法的充分条件是:

1、搜索树上存在着从起始点到终了点的最优路径。

2、问题域是有限的。

3、所有结点的子结点的搜索代价值>0。

4、h=<h* (h*为实际问题的代价值)。

当此四个条件都满足时,一个具有f=g+h策略的启发式算法能成为A*算法,并一定能找到最优解。

对于一个搜索问题,显然,条件1,2,3都是很容易满足的,而条件4: h<=h*是需要精心设计的,由于h*显然是无法知道的,所以,一个满足条件4的启发策略h就来的难能可贵了。

且h距离h*的呈度不能过大,否则h就没有过强的区分能力,算法效率并不会很高。对一个好的h的评价是:h在h*的下界之下,并且尽量接近h*。                                                                                                                               ---v_JULY_v

h距离一般可以使用三种方法:

1. Manhattan: h = x + y

2. Euclidean: h = hypot(x, y)

3. Chebyshev: h = max(x, y)

              ---(x,y)是当前点距离目标点之间的坐标距离差 

也可以定义f = g + W * h;

---W权重越大heuristic function越重要

        算法最为核心的过程,就在每次选择下一个当前搜索点时,是从所有已探知的但未搜索过点中可能是不同层,亦可不在同一条支路上),选取f值最小的结点进行展开。而所有“已探知的但未搜索过点”可以通过一个按f值升序的队列(即优先队列)进行排列。这样,在整体的搜索过程中,只要按照类似BFS的算法框架,从优先队列中弹出队首元素(f值),对其可能子结点计算g、h和f值,直到优先队列为空(无解)或找到终止点为止。                                    ---v_JULY_v


示例:


#include <iostream>  

#include <queue>

#include <vector>


bool visited[19][38]; //定义是否被访问

short int map[19][38] = {

{1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1},

{1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1},

{1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1},

{0,1,1,1,1,0,0,0,0,0,1,0,1,0,1,1,1,1,1,0,0,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1},

{1,0,0,0,0,0,1,1,1,0,1,1,1,0,1,1,1,1,0,1,0,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1},

{1,1,1,1,1,0,1,1,1,1,0,0,0,0,0,1,1,0,1,1,0,1,1,1,1,0,0,0,1,1,1,1,0,0,1,1,1,1},

{1,1,1,1,0,0,1,1,1,1,1,1,1,0,1,0,0,1,1,1,1,1,1,0,1,1,1,1,1,1,1,0,1,1,1,1,1,1},

{1,1,1,1,1,0,1,1,1,1,1,1,1,1,0,1,0,1,1,1,1,1,1,1,1,1,1,0,0,0,0,1,1,1,1,1,1,0},

{1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,0,0},

{1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,1,1,1,1,1,0,0,0,0,1,1},

{1,1,1,1,1,1,1,1,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,0,0,1,1,1,1,1,1},

{1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,0,0,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1},

{1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,0,0,1,1,1,1,1,1,1,0,0,0,0,0,0,1,1,1},

{1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1},

{1,1,1,1,1,1,1,1,1,0,0,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},

{1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,0,0,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1},

{1,1,1,1,1,1,1,1,1,1,0,0,1,1,1,1,1,0,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1},

{1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1},

{1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1},

};


int g_startx = 0;

int g_starty = 0;

int g_endx = 15;

int g_endy = 36;


struct node

{

int f,g,h; int x,y; node *p; // p指向parent

Point node():x(0),y(0),f(0),g(0),h(0),p(NULL){} };

struct Node

{

//It is convenient to use priority queue

node *p_node;

bool operator<(const Node &f_n) const

{

//define method of priority queue

return p_node->f > f_n.p_node->f;

}


};

vector<node *> g_vector;


bool inmap(int x, int y) //坐标是否在有效范围内

{


if(x >= 0 && y >= 0 && x <= 18 && y <= 37)

return true;

return false;

}


int heuristic(int x, int y) //heuristic function

{

//The goal of * 10 is convenient to calculate 

//return 0;

//Manhattan

return (int)10 * (fabs((double)(g_endx-x)) + fabs((double)(g_endy - y)));

//Chebyshev

//return (int)10 * max(fabs((double)(g_endx-x)),fabs((double)(g_endy - y)));

}


void retrace(node *n) //找寻回路

{

while(n)

{

map[n->x][n->y] = 3;

if(n->x == 0 && n->y == 0)

{

return;

}

n = n->p;

}

}

bool wall(int x, int y,int xx,int yy) //判断夹墙效果

{

//if child point is jacketed wall point return bool

if(map[x+dirs[0][0]][y+dirs[0][1]] == 0 && map[x+dirs[2][0]][y+dirs[2][1]] == 0 && 

xx ==  x+dirs[1][0] && yy == y+dirs[1][1] )

{

return true;

}

else if(map[x+dirs[4][0]][y+dirs[4][1]] == 0 && map[x+dirs[2][0]][y+dirs[2][1]] == 0 && 

xx ==  x+dirs[3][0] && yy == y+dirs[3][1] )

{

return true;

}

else if(map[x+dirs[4][0]][y+dirs[4][1]] == 0 && map[x+dirs[6][0]][y+dirs[6][1]] == 0&& 

xx ==  x+dirs[5][0] && yy == y+dirs[5][1] )

{

return true;

}

else if(map[x+dirs[0][0]][y+dirs[0][1]] == 0 && map[x+dirs[6][0]][y+dirs[6][1]] == 0 && 

xx ==  x+dirs[7][0] && yy == y+dirs[7][1] )

{

return true;

}

else

return false;

}


void Astar() //采用优先级队列保存节点,以node.f 作为判断标准

{

priority_queue<Node > pq;

Node l_Node;

node *l_startnode = new node;

g_vector.push_back(l_startnode);

l_startnode->x = g_startx;

l_startnode->y = g_starty;

l_startnode->g = 0;

l_startnode->h = heuristic(l_startnode->x ,l_startnode->y);

l_startnode->f = l_startnode->g + l_startnode->h;

l_startnode->p = NULL;


l_Node.p_node = l_startnode;

pq.push(l_Node);

int px,py;

int cx,cy;

cx = cy = px = py = 0;

node *l_parent;


while(!pq.empty())

{

l_Node = pq.top();

pq.pop();

l_parent = l_Node.p_node;

px = l_parent->x;

py = l_parent->y;


if(px == g_endx && py == g_endy) 

{

retrace(l_parent);

return;

}

else if(!visited[px][py]) 

{

visited[px][py] = true;

node *tmp;

for(int i = 0; i < 8; i++)

{

cx = px + dirs[i][0];

cy = py + dirs[i][1];

if(i % 2 == 1)

{

if(wall(px,py,cx,cy)) //夹墙点放弃

continue;

}

if(inmap(cx,cy) && map[cx][cy] && !visited[cx][cy]) // 保存未被访问过、非墙壁、在地图中的相邻节点

{

tmp = new node();

g_vector.push_back(tmp);

tmp->x = cx;

tmp->y = cy;

if(i%2 == 1) //if abs(dirs[i][0]) == 1 && abs(dirs[i][1] == 1) The distance of two point is 14

{

tmp->g = l_parent->g + 14;

}

else

{

tmp->g = l_parent->g + 10;

}

tmp->h = heuristic(tmp->x,tmp->y);

tmp->f = tmp->g + tmp->h;

tmp->p = l_parent;

l_Node.p_node = tmp;

pq.push(l_Node);

}

}

}

}

}


void deleteNode() //free node memory

{

vector<node *>::iterator start = g_vector.begin(); 

node *tmp;

while(start != g_vector.end())

{

tmp = *start;

start = g_vector.erase(start);

delete tmp;

}

}


int main()

{

Astar();

for(int x = 0; x < 19; x++)

{

for(int y = 0; y < 38; y++)

{


if(x == g_startx && y == g_starty)

{

cout<<" S ";

continue;

}

if(x == g_endx && y == g_endy)

{

cout<<" T ";

continue;

}


if(map[x][y] == 3 )

cout<<" /3 ";

/*else if(visited[x][y] )

cout<<" /2 ";*/

else if(map[x][y] == 0)

cout<<" x ";

else

cout<<"   ";

}

cout<<endl;

}

deleteNode();

return 0;

}

参考:

A* Pathfinding for Beginners http://www.policyalmanac.org/games/aStarTutorial.htm

A formal basis for the heuristic determination of minimum cost paths in graphs(论文)

A*搜索算法 -- http://blog.csdn.net/v_JULY_v/archive/2010/12/23/6093380.aspx

Path Finding http://code.google.com/p/mycodeplayground/

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值