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;
}