AtCoder题解 —— AtCoder Beginner Contest 184 —— C - Super Ryuma

题目相关

题目链接

AtCoder Beginner Contest 184 C 题,https://atcoder.jp/contests/abc184/tasks/abc184_c

Problem Statement

There is an infinite two-dimensional grid, and we have a piece called Super Ryuma at square (r1,c1). (Ryu means dragon and Ma means horse.) In one move, the piece can go to one of the squares shown below:

More formally, when Super Ryuma is at square (a,b), it can go to square (c,d) such that at least one of the following holds:

  • a+b=c+d
  • a−b=c−d
  • |a−c|+|b−d|≤3

Find the minimum number of moves needed for the piece to reach (r2,c2) from (r1,c1).

Input

Input is given from Standard Input in the following format:

r1 c1
r2 c2

Output

Print the minimum number of moves needed for Super Ryuma to reach (r2,c2) from (r1,c1).

Samples1

Sample Input 1

1 1
5 6

Sample Output 1

2

Explaination

We need two moves - for example, (1,1)→(5,5)→(5,6).

Samples2

Sample Input 2

1 1
1 200001

Sample Output 2

2

Explaination

We need two moves - for example, (1,1)→(100001,100001)→(1,200001).

Samples3

Sample Input 3

2 3
998244353 998244853

Sample Output 3

3

Explaination

We need three moves - for example, (2,3)→(3,3)→(−247,253)→(998244353,998244853).

Samples4

Sample Input 4

1 1
1 1

Sample Output 4

0

Constraints

  • All values in input are integers.
  • 1≤r1,c1,r2,c2≤10^9

题解报告

题目翻译

有一个无限的二维网格,在坐标 (r1, c1) 处有一个超级龙马,每次这个超级龙马可以移动如上图的位置。更加准确的说,当超级龙马在坐标 (a, b),它可以移动到坐标 (c, d) 只要满足下面的条件:

  • a+b=c+d
  • a−b=c−d
  • |a−c|+|b−d|≤3

请找出从 (r1, c1) 移动到 (r2, c2) 的最少的移动步数。

移动方法分析

规则一:a+b=c+d

当前位置为 (a, b)。

1、我们向右下移动一格,对应的坐标为 (a-1, b+1);

2、我们向右下移动 n 格,对应的坐标为 (a-n, b+n);

3、我们向左上移动一格,对应的坐标为 (a+1, b-1);

4、我们向左上移动 n 格,对应的坐标为 (a+n, b- n);

我们可以发现,满足条件 c+d=a+b,也就是满足条件一。也就是副对角线方向运动,如下图所示。

规则二:a-b=c-d

当前位置为 (a, b)。

1、我们向左下移动一格,对应的坐标为 (a+1, b+1);

2、我们向左下移动 n 格,对应的坐标为 (a+n, b+n);

3、我们向右上移动一格,对应的坐标为 (a-1, b-1);

4、我们向右上移动 n 格,对应的坐标为 (a-n, b- n);

我们可以发现,满足条件 c-d=a-b,也就是满足条件二。也就是主对角线方向运动,如下图所示。

规则三:|a−c|+|b−d|≤3

自然就是图片中中间部分。如下图所示。

下面我们根据这个来分析一下样例数据。

样例数据分析

样例数据 1

根据样例数据 1,我们需要从 (1, 1) 到 (5, 6)。

先用规则二,沿着主对角线移动,从 (1, 1) 移动到 (5, 5);

再用规则三,从 (5,5) 移动到 (5, 6)。

样例数据 2

根据样例数据 2,我们需要从 (1, 1) 到 (1, 200001)。

先用规则二,沿着主对角线移动,从 (1, 1) 移动到 (100001, 100001);

再用规则一,沿着副对角线移动,从 (100001, 100001) 移动到 (1, 200001)。

样例数据 3

根据样例数据 3,我们需要从 (2, 3) 到 (998244353, 998244853)。

先规则三,从 (2,3) 到 (3, 3);

再用规则一,沿着副对角线移动,从 (3, 3) 到 (-247, 253);

再用规则二,沿着主对角线移动,从 (-247, 253) 移动到 (998244353, 998244853)。

题目分析

本题又是一个数学题。根据上面的分析,我们可以总结出,从 (r1, c1) 移动到 (r2, c2),超级龙马的移动可能有以下几种可能:

移动次数为 0 次

这个比较简单。也就是起点坐标和终点坐标重合,即 r1==r2 && c1==c2。

移动次数为 1 次

也就是超级龙马可以根据任意一条规则从 (r1, c1) 移动到 (r2, c2)。这样,有三条规则可以满足这个要求。

根据规则一,可以得到条件为 r1+r2==c1+c2;

根据规则二,可以得到条件为 r1-r2==c1-c2;

根据规则三,可以得到条件为 abs(r1-r2)+abs(c1-c2)<=3。

移动次数为 2 次

这是一个组合问题,也就是超级龙马要使用两次规则。我们可以通过遍历也就是先按照规则三移动一次,再判断利用其他规则能否到达目的地即可。具体的实现可以参看下面的 AC 代码。

还有一个特殊情况是起点坐标之和和终点坐标之和奇偶性相同。参考样例输入 2。

移动次数为 3 次

剩下的情况就移动三次肯定可以到达。

AC 参考代码

//https://atcoder.jp/contests/abc184/tasks/abc184_c
//C - Super Ryuma
#include <bits/stdc++.h>

using namespace std;

//如果提交到OJ,不要定义 __LOCAL
#define __LOCAL

int main() {
#ifndef __LOCAL
    //这部分代码需要提交到OJ,本地调试不使用
    ios::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);
#endif
    int r1,c1,r2,c2;
    cin>>r1>>c1>>r2>>c2;

    int ans;
    if (r1==r2 && c1==c2) {
        ans=0;
    } else if (r1+c1==r2+c2) {
        ans=1;
    } else if (r1-c1==r2-c2) {
        ans=1;
    } else if (abs(r1-r2)+abs(c1-c2)<=3) {
        ans=1;
    } else if ((r1+c1)%2==(r2+c2)%2) {
        ans=2;
    } else {
        ans=3;

        bool flag=true;
        for (int i=-3; i<=3 && true==flag; i++) {
            for (int j=-3; j<=3; j++) {
                //判断不能操作3
                if (abs(i)+abs(j)<=3) {
                    //计算新位置
                    int xx=r2+i;
                    int yy=c2+j;
                    if (r1+c1==xx+yy) {
                        ans=2;
                        flag=false;
                        break;
                    }
                    if (r1-c1==xx-yy) {
                        ans=2;
                        flag=false;
                        break;
                    }
                    if (abs(r1-xx)+abs(c1-yy)<=3) {
                        ans=2;
                        flag=false;
                        break;
                    }
                }
            }
        }
    }

    cout<<ans<<"\n";

#ifdef __LOCAL
    //这部分代码不需要提交到OJ,本地调试使用
    system("pause");
#endif

    return 0;
}

注意,我上面的写法只是为了方便自己在 VsCode 上调试。

时间复杂度

O(1)。

空间复杂度

O(1)。

  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 5
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

努力的老周

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值