2016.11.11
【题目描述】
1043.跳马
时限:1000ms 内存限制:10000K 总时限:3000ms
描述
现有一200*200大小的国际象棋棋盘,棋盘中仅有一个马,给定马的当前位置(S)和目标位置(T),求出马最少需要多少跳才能从当前位置到达目标位置。
输入
本题包含多个测例。输入数据的第一行有一个整数N(1<=N<=1000),表示测例的个数,接下来的每一行有四个以空格分隔的整数,分别表示马当前位置及目标位置的横、纵坐标C(x,y)和G(x,y)。坐标由1开始。
输出
对于每个测例,在单独的一行内输出一个整数,即马从当前位置跳到目标位置最少的跳数。
输入样例
2
1 1 2 1
1 5 5 1
输出样例
3
4
【解题思路】
双向广搜,维护两个队列,分别从起点和终点搜索,碰头的时候结束。
双向队列扩展的小技巧,优先扩展节点数较少的队列
【代码实现】
# include <stdio.h>
# include <queue>
using namespace std;
int dx[10] = {0, 1, 2, 2, 1, -1, -2, -2, -1};
int dy[10] = {0, -2, -1, 1, 2, 2, 1, -1, -2};
int used[3][205][205];
struct coordinate {
int x, y;
}start, end;
queue<coordinate> q[3];
void init(void);
int bfs(int , int );
int can(int ,int );
coordinate move(coordinate , int );
int main(void)
{
int n, num, k;
int a, b;
scanf("%d", &n);
while (n--)
{
k = 0;
init();
while(q[1].size())
{
if (q[1].size() < q[2].size())
num = bfs(k, 1);
else
num = bfs(k, 2);
if (num != -1)
break;
}
printf("%d\n", num);
while(q[1].size())
q[1].pop();
while(q[2].size())
q[2].pop();
}
return 0;
}
int bfs(int k,int m)
{
int i;
coordinate t1,t2;
t1 = q[m].front();
q[m].pop();
for (i = 1; i <= 8; ++i)
{
if (can(t1.x+dx[i],t1.y+dy[i]))
{
t2 = move(t1, i);
if (used[3-m][t2.x][t2.y] != -1)
return used[3-m][t2.x][t2.y] + used[m][t1.x][t1.y] + 1;
if (used[m][t2.x][t2.y] == -1)
{
used[m][t2.x][t2.y] = used[m][t1.x][t1.y] + 1;
q[m].push(t2);
}
}
}
return -1;
}
void init(void)
{
int i, j;
scanf("%d%d%d%d", &start.x, &start.y, &end.x, &end.y);
for (i = 1; i <= 200; ++i)
for (j = 1; j <= 200; ++j)
used[1][i][j] = used[2][i][j] = -1;
used[1][start.x][start.y] = 0;
used[2][end.x][end.y] = 0;
q[1].push(start);
q[2].push(end);
}
int can(int x,int y)
{
if (x <= 0 || x >= 201 || y <= 0 || y >= 201)
return 0;
return 1;
}
coordinate move(coordinate a, int k)
{
coordinate b;
b.x = a.x + dx[k];
b.y = a.y + dy[k];
return b;
}
【心得体会】
了解双向广搜的基本模式