C语言习题——3004棋盘上的距离

题目描述

国际象棋的棋盘是黑白相间的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()函数的输入机制有了更深入的了解。写下此文记录我当时抓狂的状态@@。

  • 14
    点赞
  • 28
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值