题目描述
国际象棋的棋盘是黑白相间的8 * 8的方格,棋子放在格子中间。如下图所示:
王、后、车、象的走子规则如下:
(1)王:横、直、斜都可以走,但每步限走一格。
(2)后:横、直、斜都可以走,每步格数不受限制。
(3)车:横、竖均可以走,不能斜走,格数不限。
(4)象:只能斜走,格数不限。
写一个程序,给定起始位置和目标位置,计算王、后、车、象从起始位置走到目标位置所需的最少步数。
输入
第一行是测试数据的组数t(0 <= t <= 20)。以下每行是一组测试数据,每组包括棋盘上的两个位置,第一个是起始位置,第二个是目标位置。位置用字母-数字的形式表示,字母从“a”到“h”,数字从“1”到“8”。
输出
对输入的每组测试数据,输出王、后、车、象所需的最少步数。如果无法到达,就输出“Inf”。
样例输入
2
a1 c3
f5 f8
样例输出
2 1 2 1
3 1 1 Inf
解题分析
本题需要抓住王、后、车、象不同的行走规则,根据它们的规则来确定它们分别从出发点到目标点所需要的步骤。为此我们可以按照图3.1,以数字和字母的形式规定棋盘上每个位置,这样就可以采用坐标方式来定义棋盘的起始位置和目标位置。
我们可以规定水平方向上的距离为x,也就是从a-h,垂直方向上的距离为y,也就是从1-8。
我们首先考虑一种特殊情况,就是起始位置和目标位置相同,那么全为0。这种特殊情况常常会被大家忽略掉,从而提交的程序不能通过。下面我们来考虑如果这两个位置不同的情况。
(1)王
我们先来考虑王在棋盘上从一个起始位置走到目标位置需要多少步。由于王可以横(水平)、直(垂直)、斜走(水平和垂直同时进行),每次只能走一个格,即x或y每次最多只能变化1。这样的话所需要的最少步数为,x和y的差(先斜着走,这样距离最短),剩余的在水平或垂直走,即这两者当中的最小者,写成式子就是:abs(x-y)+min(x,y)
(2)后
后的行走规则和王差不多,但是每步走的格数任意,这样从一个位置走到另外一个位置一般只有两种可能:1(可以水平直达或可以垂直直达或可以斜着直达)、2(不能直达)。简言之就是,如果x=y或x=0或y=0,则为1,否则x<>y,则为2。
(3)车
可以横、竖走,格数不限,但不能斜走。因此从一个位置到另外一个位置只需要1(能水平直达或垂直直达)或2(不能直达的,可以先水平后垂直或者先垂直后水平)
(4)象
由于象只能斜着走,格数不限,因此情况比较复杂点。
第一种:可以斜着直达,这种情况下必须满足x方向上的差值和y方向上的差值相同,那么只需要1步。
第二种:不能斜着直达的情况下,见图3.1,如果起始位置和目标位置在同一种颜色的格子里的话,那么只需要2步,也就是说如果起始位置在黑色格子里,目标位置也在黑色格子里,可以斜着从西南到东北方向(或反过来也可以)走一步,然后再从东南到西北(或者反过来)。或者同在白色格子里也是如此。
如果起始位置和目标位置不在同一色的格子里,那么无论象怎么走,都没法到达目标位置。这种情况实际上就是x与y的差值为奇数。
以上是官方题解,我的代码如下:
#include <stdio.h>
#include <math.h>
#include<stdlib.h>
int main()
{
int t;
scanf("%d",&t);
getchar();//吸收末尾的\n
for(int i = 0;i < t;i++){
int wang,hou,che,xiang;
char x1,x2;//初末位置的横坐标
int y1,y2;//初末位值的纵坐标
scanf("%c%d",&x1,&y1);
getchar();
scanf("%c%d",&x2,&y2);
getchar();
int x = abs(x1-x2);
int y = abs(y1-y2);
//处理特殊情形,起始位置和终止位置相同时
if(x==0 && y==0){
printf("0 0 0 0\n");
continue;
}
//处理王的步数
if(x == 0){
wang = y;
}else if(y == 0){
wang = x;
}else {
if(x > y)
wang = x;
else
wang = y;
}
//处理后的步数
if(x==0 || y==0 || x == y){
hou = 1;
}else{
hou = 2;
}
//处理车的步数
if(x==0 || y == 0){
che = 1;
}else{
che = 2;
}
//处理象的步数
if(x == y){ //对角线的情况
xiang = 1;
}else if((x+y) % 2 == 0){//不位于对角线且象能走到
xiang = 2;
}else{
xiang = -1;//表示象无法走到
}
//输出结果
if(xiang != -1){
printf("%d %d %d %d\n",wang,hou,che,xiang);
}else{
printf("%d %d %d Inf\n",wang,hou,che);
}
}
return 0;
}
测试结果题给样例能过但是答案错误:
分析代码,发现问题:
scanf("%d",&t);
getchar();//吸收末尾的\n
//······
scanf("%c%d",&x1,&y1);
getchar();
scanf("%c%d",&x2,&y2);
getchar();
getchar()本来想吸收输入的t后\n,但是如果在输入t的时候,按了很多个空白符呢?显然一个getchar()解决不了。后面两个输入也是同样问题。修改代码如下:
scanf(" %c%d", &x1, &y1);
scanf(" %c%d", &x2, &y2);
在scanf()函数的格式字符%c前加一个空格,scanf在输入字符时会跳过其前面的所有空白字符!!!
最后的代码如下:
#include <stdio.h>
#include <math.h>
#include<stdlib.h>
int main()
{
int t;
scanf("%d",&t);
for(int i = 0;i < t;i++){
int wang,hou,che,xiang;
char x1,x2;
int y1,y2;
scanf(" %c%d", &x1, &y1);
scanf(" %c%d", &x2, &y2);
int x = abs(x1-x2);
int y = abs(y1-y2);
//处理特殊情形,起始位置和终止位置相同时
if(x1 == x2 && y1 == y2){
printf("0 0 0 0\n");
continue;
}
//处理王的步数
if(x == 0){
wang = y;
}else if(y == 0){
wang = x;
}else {
if(x > y)
wang = x;
else
wang = y;
}
//处理后的步数
if(x1 == x2 || y1 == y2 || x == y){
hou = 1;
}else{
hou = 2;
}
//处理车的步数
if(x1 == x2 || y1 == y2){
che = 1;
}else{
che = 2;
}
//处理象的步数
if(x == 0){//同一列
if(y % 2 == 0){
xiang = 2;
}else{
xiang = -1;
}
}else if(y == 0){//同一行
if(x % 2 == 0){
xiang = 2;
}else{
xiang = -1;
}
}else {//斜线
if(x == y){
xiang = 1;
}else if((x+y) % 2 == 1){
xiang = -1;
}else{
xiang = 2;
}
}
//输出结果
if(xiang != -1){
printf("%d %d %d %d\n",wang,hou,che,xiang);
}else{
printf("%d %d %d Inf\n",wang,hou,che);
}
}
return 0;
}
ps:鬼知道我排查这么一个看似很小的bug用了多久,无论怎么输入步数觉得计算结果都没问题,样例也对,就是不给通过,简直快要崩溃了!!!这个bug对我而言很隐蔽,通过排bug我也对scanf()函数的输入机制有了更深入的了解。写下此文记录我当时抓狂的状态@@。