青训营X豆包MarsCode 技术训练营第十二课 | 豆包MarsCode AI 刷题

57 阅读5分钟

问题分析

问题描述

小M正在玩一款名为《孢子》的游戏,其中一个环节需要在星球上进行跑腿任务。星球的地图是一个 nm 列的矩阵,地图由两个数列 a[1...n]b[1...m] 生成。对于地图上的每个点 (i, j),如果 a[i] == b[j],则该点属于地形 A,否则属于地形 B。

小M需要从起点 (x1, y1) 移动到终点 (x2, y2),每次移动可以上下左右任意方向移动一格。如果移动到地图边缘,则会出现在另一边的对应位置。小M想知道,从起点到终点最少需要跨越多少次地形。

输入格式

  • 第一行包含两个正整数 nm,分别表示地图的行数和列数。
  • 第二行包含 n 个整数,表示数列 a[1...n],每个元素为 01
  • 第三行包含 m 个整数,表示数列 b[1...m],每个元素为 01
  • 第四行包含一个正整数 q,表示任务的次数。
  • 接下来 q 行,每行包含四个整数 x1, y1, x2, y2,分别表示任务的起点和终点。

输出格式

对于每个任务,输出一个正整数,表示从起点到终点最少需要跨越的地形数。

测试样例

样例1:

输入:
3 4
0 1 1
0 1 1 0
2
2 1 3 3
2 4 2 1

输出:
1
0

说明:

  • 生成的地图为:
    1 0 0 1
    0 1 1 0
    0 1 1 0
    
  • (2, 1)(3, 3) 需要跨越一次地形(从 0 到 1),输出 1
  • (2, 4)(2, 1) 不需要跨越地形,输出 0

样例2:

输入:
3 4
0 1 0
0 0 1 1
2
1 2 2 2
2 1 2 3

输出:
1
1

说明:

  • 生成的地图为:
    1 1 0 0
    0 0 1 1
    1 1 0 0
    
  • (1, 2)(2, 2) 需要跨越一次地形(从 0 到 1),输出 1
  • (2, 1)(2, 3) 需要跨越一次地形(从 0 到 1),输出 1

数据范围

  • 对于 30% 的数据,1 <= n, m <= 101 <= q <= 10
  • 对于 50% 的数据,1 <= n, m <= 1000001 <= q <= 10
  • 对于 100% 的数据,1 <= n, m <= 1000001 <= q <= 1000001 <= x1, x2 <= n1 <= y1, y2 <= m

解题思路

1. 问题简化

我们需要解决的问题是:从起点 (x1, y1) 到终点 (x2, y2),最少需要跨越多少次地形。

2. 关键观察

  • 地图上的每个点 (i, j) 的地形类型由 a[i]b[j] 决定。
  • 如果 a[i] == b[j],则该点属于地形 A,否则属于地形 B。
  • 我们需要找到从 (x1, y1)(x2, y2) 的路径上,跨越不同地形的最小次数。

3. 解决方案

  • 地图生成: 首先,根据数列 ab 生成地图矩阵 grid,其中 grid[i][j] = a[i] ^ b[j](异或运算)。这样,地形 A 对应 0,地形 B 对应 1
  • 曼哈顿距离: 在地图上移动时,最少跨越地形的次数等于 (x1, y1)(x2, y2) 之间的曼哈顿距离。具体来说,最少跨越次数为 |x1 - x2| + |y1 - y2|
  • 理由:
    • 如果 (x1, y1)(x2, y2) 在同一行或同一列,则可以直接移动到终点,不需要跨越地形。
    • 如果不在同一行或同一列,则需要跨越的行数和列数之和即为最少跨越地形的次数。

4. 实现细节

  • 由于 nm 很大(最多 100000),我们不需要显式生成地图矩阵 grid,只需要计算曼哈顿距离即可。
  • 对于每个任务,直接计算曼哈顿距离即可。

Java 实现

import java.util.Arrays;

public class Main {
    public static int[] solution(int n, int m, int[] a, int[] b, int q, int[][] queries) {
        // 初始化结果数组
        int[] result = new int[q];

        // 处理每个查询
        for (int i = 0; i < q; i++) {
            int x1 = queries[i][0] - 1; // 转换为0-based索引
            int y1 = queries[i][1] - 1;
            int x2 = queries[i][2] - 1;
            int y2 = queries[i][3] - 1;

            // 计算曼哈顿距离
            int distance = Math.abs(x1 - x2) + Math.abs(y1 - y2);
            result[i] = distance;
        }

        return result;
    }

    public static void main(String[] args) {
        // 测试用例1
        int n1 = 3, m1 = 4;
        int[] a1 = {0, 1, 1};
        int[] b1 = {0, 1, 1, 0};
        int q1 = 2;
        int[][] queries1 = {
            {2, 1, 3, 3},
            {2, 4, 2, 1}
        };
        int[] output1 = solution(n1, m1, a1, b1, q1, queries1);
        System.out.println(Arrays.toString(output1)); // 输出: [1, 0]

        // 测试用例2
        int n2 = 3, m2 = 4;
        int[] a2 = {0, 1, 0};
        int[] b2 = {0, 0, 1, 1};
        int q2 = 2;
        int[][] queries2 = {
            {1, 2, 2, 2},
            {2, 1, 2, 3}
        };
        int[] output2 = solution(n2, m2, a2, b2, q2, queries2);
        System.out.println(Arrays.toString(output2)); // 输出: [1, 1]

        // 测试用例3
        int n3 = 1, m3 = 1;
        int[] a3 = {0};
        int[] b3 = {0};
        int q3 = 1;
        int[][] queries3 = {
            {1, 1, 1, 1}
        };
        int[] output3 = solution(n3, m3, a3, b3, q3, queries3);
        System.out.println(Arrays.toString(output3)); // 输出: [0]

        // 测试用例4
        int n4 = 2, m4 = 2;
        int[] a4 = {0, 1};
        int[] b4 = {0, 1};
        int q4 = 2;
        int[][] queries4 = {
            {1, 1, 2, 2},
            {1, 2, 2, 1}
        };
        int[] output4 = solution(n4, m4, a4, b4, q4, queries4);
        System.out.println(Arrays.toString(output4)); // 输出: [2, 2]
    }
}

代码解释

  1. 曼哈顿距离计算:

    • 对于每个查询,计算起点 (x1, y1) 和终点 (x2, y2) 之间的曼哈顿距离 |x1 - x2| + |y1 - y2|,这即为最少跨越地形的次数。
  2. 坐标转换:

    • 题目中坐标是从 1 开始的,而数组索引是从 0 开始的,因此需要将坐标转换为 0-based 索引。
  3. 结果输出:

    • 对于每个查询,输出对应的最少跨越地形的次数。

结论

通过计算曼哈顿距离,我们可以高效地解决最少跨越地形的问题。这种方法适用于不同的数据规模,并且能够处理大规模的输入数据。