http://poj.org/problem?id=2243
问题概述:一个8*8的棋盘,给定一个起点(列a-h,行1-8)和一个终点(列a-h,行1-8),按骑士的走法(走日字),从起点到
终点最少移动多少次
输入样例: 对应输出:
e2 e4 To get from e2 to e4 takes 2 knight moves.
a1 b2 To get from a1 to b2 takes 4 knight moves.
b2 c3 To get from b2 to c3 takes 2 knight moves.
a1 h8 To get from a1 to h8 takes 6 knight moves.
a1 h7 To get from a1 to h7 takes 5 knight moves.
h8 a1 To get from h8 to a1 takes 6 knight moves.
b1 c3 To get from b1 to c3 takes 1 knight moves.
f6 f6 To get from f6 to f6 takes 0 knight moves.
双向BFS:
起点终点同时BFS,直到它们相交即停止,这时最短路便是交点到起点和终点的最短路之和
http://blog.csdn.net/wdkirchhoff/article/details/41121517
时间复杂度:设BFS的复杂度为n,则双向BFS的复杂度为[2*sqrt(n),n]
http://www.ihypo.net/1614.html
和BFS的不同:
1、需要两个队列
2、不仅要标记有没有走过,而且还要进行区分标记,来记录到底是从起点走到当前点的还是从终点走到当前点的
3、要设定距离数组,表示从起点到当前位置的最短距离(因为有两个起点,而在结构体里定义最短距离只能实时更
新一个值)
#include<stdio.h>
#include<string.h>
#include<queue>
using namespace std;
typedef struct
{
int x;
int y;
int t;
}Point;
Point now, temp; /*dir[i][j]为方向数组,走日字可以往8个方向走*/
int use[11][11], dp[11][11], dir[8][2] = {-1,-2,1,-2,-2,-1,2,-1,-2,1,2,1,-1,2,1,2};
/*use[i][j]==1表示点(i,j)被以起点开始的广搜搜到过,use[i][j]==1表示点(i,j)被以终点开始的广搜搜到过,use[i][j]==0表示还没被搜到*/
/*dp[i][j]表示点(i,j)到其中一个起点的最短路(看这个点被哪个起点开始的搜索先搜到)*/
queue<Point> q1, q2;
int main(void)
{
int i, x1, y1, x2, y2, ans;
char c1, c2;
while(scanf(" %c%1d %c%1d", &c1, &x1, &c2, &x2)!=EOF)
{
ans = -1;
memset(use, 0, sizeof(use));
memset(dp, 0, sizeof(dp));
y1 = c1-96;
y2 = c2-96;
if(x1==x2 && y1==y2) /*当起点等于终点*/
{
printf("To get from %c%d to %c%d takes %d knight moves.\n", c1, x1, c2, x2, 0);
continue;
}
now.x = x1, now.y = y1, now.t = 0;
q1.push(now); /*起点进入第一个队列*/
use[now.x][now.y] = 1;
now.x = x2, now.y = y2;
q2.push(now); /*终点进入第二个队列*/
use[now.x][now.y] = -1;
while(q1.empty()==0 || q2.empty()==0)
{
if(q1.empty()==0) /*如果第一个队列不为空*/
{
now = q1.front();
q1.pop();
for(i=0;i<=7;i++)
{
temp.x = now.x+dir[i][0];
temp.y = now.y+dir[i][1];
temp.t = now.t+1;
if(temp.x>=1 && temp.x<=8 && temp.y>=1 && temp.y<=8 && use[temp.x][temp.y]!=1) /*如果这个点还没被搜过或只被以终点开始的广搜搜过*/
{
if(use[temp.x][temp.y]==-1) /*如果这个点被以终点开始的广搜搜过,说明最短路已经被找到*/
{
while(q1.empty()==0)
q1.pop();
while(q2.empty()==0) /*两个队列全部清0*/
q2.pop();
ans = temp.t+dp[temp.x][temp.y]; /*算出最短路=起点与终点到当前点最短路之和*/
break;
}
use[temp.x][temp.y] = 1;
dp[temp.x][temp.y] = temp.t;
q1.push(temp);
}
}
}
if(q2.empty()==0) /*同上*/
{
now = q2.front();
q2.pop();
for(i=0;i<=7;i++)
{
temp.x = now.x+dir[i][0];
temp.y = now.y+dir[i][1];
temp.t = now.t+1;
if(temp.x>=1 && temp.x<=8 && temp.y>=1 && temp.y<=8 && use[temp.x][temp.y]!=-1)
{
if(use[temp.x][temp.y]==1)
{
while(q2.empty()==0)
q2.pop();
while(q1.empty()==0)
q1.pop();
ans = temp.t+dp[temp.x][temp.y];
break;
}
use[temp.x][temp.y] = -1;
dp[temp.x][temp.y] = temp.t;
q2.push(temp);
}
}
}
}
printf("To get from %c%d to %c%d takes %d knight moves.\n", c1, x1, c2, x2, ans);
}
return 0;
}