poj 2243(A*搜索orBFS)

来源:互联网 发布:dijkstra算法优先队列 编辑:程序博客网 时间:2024/04/30 14:40

Knight Moves

以前听说过A*搜索这个推崇备至的算法,但没有去认真阅读过相关资料,今天(2013/10/0D)认真学习了一下

通过这题学习了A*搜索,下面就来描述一下A*搜索的详细过程:

   1,把起始格添加到开启列表。
   2,重复如下的工作:
      a) 寻找开启列表中F值最低的格子。我们称它为当前格。
      b) 把它切换到关闭列表。
      c) 对相邻的格中的每一个?
          * 如果它不可通过或者已经在关闭列表中,略过它。反之如下。
          * 如果它不在开启列表中,把它添加进去。把当前格作为这一格的父节点。记录这一格的F,G,和H值。
          * 如果它已经在开启列表中,用G值为参考检查新的路径是否更好。更低的G值意味着更好的路径。如果是这样,就把这一格的父节点改成当前格,并且重新计算这一格的G和F值。如果你保持你的开启列表按F值排序,改变之后你可能需要重新对开启列表排序。
      d) 停止,当你
          * 把目标格添加进了关闭列表(注解),这时候路径被找到,或者
          * 没有找到目标格,开启列表已经空了。这时候,路径不存在。
   3.保存路径。从目标格开始,沿着每一格的父节点移动直到回到起始格。这就是你的路径。

下面就来做题巩固一下:
poj  2243  Knight Moves

题目的意思大概是说:在国际象棋的棋盘上,一匹马共有8个可能的跳跃方向,求从起点到目标点之间的最少跳跃次数。

内存:176K      耗时 :  32MS  (将队列定义为全局,可减少时间)

#include <iostream>#include <cstdio>#include <cstring>#include <queue>#include <cmath>using namespace std;struct knight{    int x,y,step;    int f,g,h;//启发:f=g+h;    bool operator <(const knight& a)const{      return  f>a.f;//重载<,每次选择代价最小的    }    bool operator ==(const knight& a)    {        return (x==a.x&&y==a.y)?1:0;    }    bool ok()    {        if(x>=0&&x<8&&y>=0&&y<8)            return 1;        else            return 0;    }}s,e;bool vis[8][8];//已访问列表int dir[8][2]={{-2,-1},{-2,1},{-1,2},{1,2},{2,1},{2,-1},{1,-2},{-1,-2}};priority_queue<knight>Q;//定义为全局可减少时间int Heuristic(const knight& a){   //用曼哈顿距离作为估值函数    return (abs(a.x-e.x)+abs(a.y-e.y))*10;//距离扩大10倍}int Astar(){    memset(vis,0,sizeof(vis));    while(!Q.empty())        Q.pop();    Q.push(s);    vis[s.x][s.y]=1;    if(s==e)return 0;    knight pre,now;    while(!Q.empty())    {        pre=Q.top();        Q.pop();        for(int i=0;i<8;i++)        {            now.x=pre.x+dir[i][0];            now.y=pre.y+dir[i][1];            now.step=pre.step+1;            if(now.ok()&&!vis[now.x][now.y])            {                if(now==e) return now.step;                now.g=pre.g+22;//这里为√5*10                now.h=Heuristic(now);                now.f=now.g+now.h;                Q.push(now);                vis[now.x][now.y]=1;//标记该点已访问            }        }    }    return -1;}int main(){    char s1[3],s2[3];    while(~scanf("%s%s",s1,s2))    {        s.x=s1[0]-'a';s.y=s1[1]-'1';        s.f=s.g=s.h=s.step=0;        e.x=s2[0]-'a';        e.y=s2[1]-'1';        int ans=Astar();        printf("To get from %s to %s takes %d knight moves.\n",s1,s2,ans);    }    return 0;}

之后,我又用BFS做了一下:(从这个题看不出什么差距,可能数据量不大)
Accepted   176K  耗时: 16MS

#include <iostream>#include <cstdio>#include <cstring>#include <queue>using namespace std;int step[8][8];struct node{    int x,y;};int dir[8][2]={{-2,-1},{-2,1},{-1,2},{1,2},{2,1},{2,-1},{1,-2},{-1,-2}};queue <node> q;int BFS(node begin,node end){    memset(step,0,sizeof(step));    while(!q.empty())      q.pop();    node temp,next;    q.push(begin);    while(!q.empty())    {        temp=q.front();        q.pop();        for(int i=0;i<8;i++)        {            next.x=temp.x+dir[i][0];            next.y=temp.y+dir[i][1];            if(next.x<0||next.x>=8||next.y<0||next.y>=8)                continue;            if(step[next.x][next.y]>0)                continue;            step[next.x][next.y]=step[temp.x][temp.y]+1;            q.push(next);            if(next.x==end.x && next.y==end.y)                return step[next.x][next.y];        }    }    return -1;}int main (){    char s1[3],s2[3];    node begin,end;    while(scanf("%s%s",s1,s2)!=EOF)    {        if(strcmp(s1,s2)==0)        {            printf("To get from %s to %s takes 0 knight moves.\n",s1,s2);            continue;        }        begin.x=s1[1]-'1';begin.y=s1[0]-'a';        end.x=s2[1]-'1';end.y=s2[0]-'a';        printf("To get from %s to %s takes %d knight moves.\n",s1,s2,BFS(begin,end));    }    return 0;}