华为OD机试【亲子游戏】(java)(200分)

1、题目描述

宝宝和妈妈参加亲子游戏,在一个二维矩阵(N*N)的格子地图上,宝宝和妈妈抽签决定各自的位置,地图上每个格子有不同的糖果数量,部分格子有障碍物。
游戏规则是妈妈必须在最短的时间(每个单位时间只能走一步)到达宝宝的位置,路上的所有糖果都可以拿走,不能走障碍物的格子,只能上下左右走。
请问妈妈在最短到达宝宝位置的时间内最多拿到多少糖果(优先考虑最短时间到达的情况下尽可能多拿糖果)。

2、输入描述

第一行输入为 N,N 表示二维矩阵的大小
之后 N 行,每行有 N 个值,表格矩阵每个位置的值,其中:
● -3:妈妈
● -2:宝宝
● -1:障碍
● ≥0:糖果数(0表示没有糖果,但是可以走)

3、输出描述

输出妈妈在最短到达宝宝位置的时间内最多拿到多少糖果,行末无多余空格。
用例:

输入
4
3 2 1 -3
1 -1 1 1
1 1 -1 2
-2 1 2 3

输出
9

ps:此地图有两条最短路径可到达宝宝位置,绿色线和黄色线都是最短路径6步,但黄色拿到的糖果更多,9个

用例:

输入
4
3 2 1 -3
-1 -1 1 1
1 1 -1 2
-2 1 -1 3

输出
-1

ps:此地图妈妈无法到达宝宝位置

温馨提示!!!
华为OD机试考试官方会对考生代码查重。华为od机试因为有题库所以有很大的概率抽到原题。如果碰到了题库中的原题,千万不要直接使用题解中的代码,一定要做些修改,比如代码中的变量名,除此之外,代码的组织结构和逻辑也要进行一些改变,所以在日常的刷题中,要提前编写好属于自己的代码。

4、题解

本题可使用广度优先搜索(BFS)解答,定义一个队列存放起始点信息,使用一个三维数组记录每个位置的最短步数和糖果数量,队列不为空时则循环获取队列中的节点,如果当前节点是终点(宝宝位置),则更新最大糖果数并继续循环,分别向上下左右四个方向移动,计算新的位置并判断是否有效,计算到达新位置的糖果数和步数,如果新位置未访问过,或者可以以更少的步数到达,或者步数相同但糖果数更多,则更新三维数组并将新位置的信息加入队列。
代码如下:

public static void main(String[] args) {
    Scanner sc = new Scanner(System.in);
    int n = Integer.parseInt(sc.nextLine());
    int[][] arr = new int[n][n];
    for (int i=0; i<n; i++) {
        arr[i] = Arrays.stream(sc.nextLine().split(" "))
                .mapToInt(Integer::parseInt).toArray();
    }

    int maxSum = 0;
    boolean flag = false;
    // 记录步数与糖果数
    int[][][] visited = new int[n][n][2];
    for (int[][] v : visited) {
        for (int[] item : v) {
            Arrays.fill(item, -1);
        }
    }

    // 初始化队列
    Queue<Node> queue = new LinkedList<>();
    for (int i=0; i<n; i++) {
        for (int j=0; j<n; j++) {
            // 起始点
            if (arr[i][j] == -3) {
                Node node = new Node(i, j, 0, 0);
                // 步数
                visited[i][j][0] = 0;
                // 糖果数
                visited[i][j][1] = 0;
                queue.add(node);
            }
        }
    }
    
    int[][] offsets = {{-1,0}, {1,0}, {0,1}, {0,-1}};
    
    // BFS搜索
    while (!queue.isEmpty()) {
        Node node = queue.poll();
        int curX = node.x;
        int curY = node.y;
        int curSum = node.sum;
        int curSteps = node.steps;
        // 到达目标则更新最大糖果数
        if (arr[curX][curY] == -2) {
            flag = true;
            maxSum = Math.max(maxSum, node.sum);
            continue;
        }
        // 向四个方向遍历
        for (int[] offset : offsets) {
            int posX = curX + offset[0];
            int posY = curY + offset[1];
            // 判断位置是否有效
            if (posX < 0 || posX >= n || posY < 0 || posY >= n 
                || arr[posX][posY] == -1) {
                continue;
            }
            // 计算新位置的糖果数
            int nowSum = curSum + Math.max(arr[posX][posY], 0);
            // 计算新位置的步数
            int nowSteps = curSteps + 1;
            // 若新位置未访问过
            // 或者可以以更少的步数到达或者步数相同但糖果数更多则更新信息并加入队列
            if (visited[posX][posY][0] == -1 || visited[posX][posY][0] > nowSteps
                    || (visited[posX][posY][0] == nowSteps 
                        && visited[posX][posY][1] < nowSum)) {
                visited[posX][posY][0] = nowSteps;
                visited[posX][posY][1] = nowSum;
                queue.add(new Node(posX, posY, nowSum, nowSteps));
            }
        }
    }
    if (!flag) {
        System.out.println(-1);
        return;
    }
    System.out.println(maxSum);

}

static class Node {
    int x;
    int y;
    int sum;
    int steps;
    public Node(int x, int y, int sum, int steps) {
        this.x = x;
        this.y = y;
        this.sum = sum;
        this.steps = steps;
    }
}

执行结果如下:
在这里插入图片描述

  • 13
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

搬砖小夫子

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

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

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

打赏作者

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

抵扣说明:

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

余额充值