描述
在中国象棋中,棋子活动的场所,叫做"棋盘",在长方形的平面上,绘有九条平行的竖线和十条平行横线相交组成,共九十个交叉点,棋子就摆在这些交叉点上。中间第五、第六两横线之间未画竖线的空白地带,称为"河界",整个棋盘就以"河界"分为相等的两部分;两方将帅坐镇、画有"米"字方格的地方,叫做"九宫"。
中国象棋中,马是威力很大的棋子。马走动的方法是一直一斜,即先横着或直着走一格,然后再斜着走一个对角线,俗称"马走斜"。马一次可走的选择点可以达到四周的八个点,故有"八面威风"之说。
我们约定最左下角点的坐标为(0,0),则最右上角的坐标为(9, 8)。上图中马在坐标(2, 2)处。它走一步可以到达坐标点(1, 0),(0, 1),(0, 3),(1, 4),(3, 4),(4, 3),(4, 1)或(3,0)。如下图所示。
我们约定当前棋盘上只有一个马,给出起点坐标和终点坐标,求从起点到终点,马最少要走几步?
输入格式:
输入的的第1行是一个整数n,表示以后会有n行数据。
从第2行开始,每行有4个整数,前2个数表示起点坐标,后2个数表示终点坐标。
输出格式:
对每行起点和终点坐标输出一个整数,表示从起点到终点最少需要走的步数。每次输出之后换行。
输入样例:
在这里给出一组输入。例如:
2
2 2 5 2
0 0 9 8
输出样例:
在这里给出相应的输出。例如:
3
7
代码长度限制
16 KB
时间限制
400 ms
内存限制
64 MB
一、问题分析及算法设计思路
该题的解法与第11题马走日是类似的,采用bfs算法递归棋盘上的每一个点,与第11题的区别是本题给定了终点,要求是从起点到终点的最短步数。我们需要改动的便是在递归的条件上加入最短路径的判断,当往后的步数超过了当前最小步数,就停止递归。当到达终点时,判断每个步数大小,若新的步数少于之前走的步数,就替换掉最小值min。
二、代码实现
#include <stdio.h>
#include <stdlib.h>
#include <memory.h>
#define true 1
#define false 0
#define MAX 20
//num是有多少走到终点的方式
int min = 32767;
int step = 1;
//最大棋盘的数组
int a[MAX][MAX];
//象棋挪动的方式
int move[8][2]= {{2,-1}, {1,-2}, {-1,-2}, {1,2}, {2,1}, {-2,-1}, {-2,1}, {-1,2}};
//广度优先遍历,输入出发点和结束点
void dfs(int x,int y,int x2,int y2)
{
//x1,y1为暂时的位置
int i, x1, y1;
//当步数大于最小值的情况就不需要继续往下了
if(step > min) return;
//当便利了全部的结点,便可返回
if(x == x2 && y == y2)
{
//成功递归一次证明有一种走完全部节点的可能性
if(step <= min) min = step;
}
else
//按照八种不同的方向走的情况
for(i=0; i<8; i++)
{
//每次递归就移动一次
x1 = x + move[i][0];
y1 = y + move[i][1];
//不能出棋盘,并且落点未被选中过
if(x1 >= 0 && x1 < 10 && y1 >= 0 && y1 < 9 && a[x1][y1] == 0)
{
//选中该落点
a[x1][y1] = true;
//落点数+1
step++;
//递归调用
dfs(x1, y1, x2, y2);
//当一次结束递归时,让步数一步步返回至原点,并且开始下一种可能性的递归
step--;
//将上一次递归选中的点再依次设置为未选中
a[x1][y1] = false;
}
}
}
int main()
{
int T, x, y, x2, y2;
scanf("%d", &T);
while(T--)
{
step = 0;
min = 32767;
scanf("%d %d %d %d", &x, &y, &x2, &y2);
memset(a, 0, sizeof(a));
a[x][y] = 1;
dfs(x, y, x2, y2);
printf("%d\n", min);
}
return 0;
}
三、测试点、