题意:
象棋中马从一个格子到另一个格子最少需要多少步
思路:
简单BFS,主要用此题练习了A*算法
A*算法,原理同BFS,只是通过启发式函数(代码中的f,为起点到该点的代价g和该点到终点的股价h的和)来进行BFS的剪枝。
源码:
#include <cstdio>
#include <cstring>
#include <cmath>
#include <algorithm>
#include <iostream>
#include <queue>
using namespace std;
#define ABS(a) (((a)>0)?(a):(-(a)))///abs,注意每个a都需要括号,总的还需要一个括号
int vis[10][10];
char str[10];
int dx[] = {-1,-2,-2,-1,1,2,2,1};///方向
int dy[] = {-2,-1,1,2,2,1,-1,-2};
int x1,x2,y1,y2,ans;///初始坐标和目的坐标,答案
struct D
{
int x,y,step;
int f,g,h;
D(){step = 0;}
D(int _x,int _y,int _step,int _f,int _g,int _h){x = _x,y = _y,step = _step;f = _f;g = _g;h = _h;}
bool operator < (const D &a)const{return f > a.f;}///在优先队列,符号需要相反,比如小的在前需要f>a.f
};///fgh分别表示启发式函数和,从初始点到此点代价,从此点到终点股价
priority_queue<D> que;///优先队列实现
int haminton(int x,int y)///曼哈顿距离
{
// printf("x = %d,y = %d,x2 = %d,y2 = %d\n",x,y,x2,y2);
int ans = ABS(x - x2) + ABS(y - y2);
// printf("ans = %d\n\n",ans);
return ans * 10;
}
bool valid(int x,int y)
{
if(x < 0 || x > 7)
return false;
if(y < 0 || y > 7)
return false;
return true;
}
int main()
{
while(gets(str) != NULL){
x1 = str[0] - 'a';
y1 = str[1] - '1';
x2 = str[3] - 'a';
y2 = str[4] - '1';
while(!que.empty())
que.pop();
if(x1 == x2 && y1 == y2){
ans = 0;
}
else{
memset(vis, 0, sizeof(vis));
vis[x1][y1] = 1;
D temp = D(x1,y1,0,haminton(x1,y1),0,haminton(x1,y1));
que.push(temp);
ans = -1;
while(!que.empty()){
temp = que.top();
que.pop();
int x = temp.x;
int y = temp.y;
int step = temp.step;
int g = temp.g;
int h = temp.h;
// printf("x = %d,y = %d,step = %d,f = %d,g = %d,h = %d\n",x,y,step,temp.f,g,h);
if(x == x2 && y == y2){
ans = step;
break;
}
for(int i=0; i<8; i++){
int tx = x + dx[i];
int ty = y + dy[i];
int tstep = step + 1;
if(!valid(tx,ty) || vis[tx][ty] == 1)
continue;
vis[tx][ty] = 1;
int tg = 23 + g;
int th = haminton(tx,ty);
temp = D(tx,ty,tstep,tg+th,tg,th);
que.push(temp);
}
}
}
printf("To get from %c%c to %c%c takes %d knight moves.\n",str[0],str[1],str[3],str[4],ans);
}
return 0;
}