华为OD机试算法:亲子游戏

题目描述

宝宝和妈妈参加亲子游戏,在一个二维矩阵(N*N)的格子地图上,宝宝和妈妈抽签决定各自的位置,地图上每个格子有不同的糖果数量,部分格子有障碍物。

游戏规则是妈妈必须在最短的时间(每个单位时间只能走一步)到达宝宝的位置,路上的所有糖果都可以拿走,不能走障碍物的格子,只能上下左右走。

请问妈妈在最短到达宝宝位置的时间内最多拿到多少糖果(优先考虑最短时间到达的情况下尽可能多拿糖果)。

输入描述

第一行输入为 N,N 表示二维矩阵的大小

之后 N 行,每行有 N 个值,表格矩阵每个位置的值,其中:

  • -3:妈妈

  • -2:宝宝

  • -1:障碍

  • ≥0:糖果数(0表示没有糖果,但是可以走)

输出描述

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

备注

地图最大 50*50

用例

输入

4
3 2 1 -3
1 -1 1 1
1 1 -1 2
-2 1 2 3

输出

9

说明

输入

4
3 2 1 -3
-1 -1 1 1
1 1 -1 2
-2 1 -1 3

输出

-1

说明

题目解析
  • 1.

    首先,我们需要找到妈妈和宝宝的位置。

  • 2.

    然后,我们可以使用广度优先搜索(BFS)算法来寻找从妈妈到宝宝的最短路径。在搜索过程中,我们需要记录每个位置的糖果数量。

  • 3.

    对于每个位置,我们可以选择上下左右四个方向进行搜索。如果下一个位置是障碍物或者已经访问过,则跳过该位置。否则,将该位置加入队列中,并更新该位置的糖果数量。

  • 4.

    最后,返回到达宝宝位置时的最大糖果数量。如果没有找到路径,则返回-1。

JS算法源码
const rl = require("readline").createInterface({ input: process.stdin });
const readline = async () => (await rl[Symbol.asyncIterator]().next()).value;

(async function () {
  const n = parseInt(await readline());

  const candy = new Array(n).fill(0).map(() => new Array(n).fill(-1));

  let queue = [];

  const matrix = [];
  for (let i = 0; i < n; i++) {
    matrix.push((await readline()).split(" ").map(Number));

    for (let j = 0; j < n; j++) {
      if (matrix[i][j] == -3) {
        candy[i][j] = 0;
        queue.push([i, j]);
      }
    }
  }

  let ans = -1;

  const offsets = [
    [-1, 0],
    [1, 0],
    [0, -1],
    [0, 1],
  ];

  while (queue.length > 0) {
    const newQueue = [];

    let flag = false;

    for (let [x, y] of queue) {
      for (let [offsetX, offsetY] of offsets) {
        const newX = x + offsetX;
        const newY = y + offsetY;

        if (
          newX < 0 ||
          newX >= n ||
          newY < 0 ||
          newY >= n ||
          matrix[newX][newY] == -1
        )
          continue;

        if (candy[newX][newY] == -1) {
          newQueue.push([newX, newY]); // 加入当前扩散层
        }

        candy[newX][newY] = Math.max(
          candy[newX][newY],
          candy[x][y] + Math.max(0, matrix[newX][newY])
        );

        if (matrix[newX][newY] == -2) {
          ans = candy[newX][newY];
          flag = true;
        }
      }
    }

    if (flag) break;

    queue = newQueue;
  }

  console.log(ans);
})();

Java算法源码
import java.util.LinkedList;
import java.util.Scanner;

public class Main {
    static int n;
    static int[][] matrix;
    static int[][] candy;
    static int[][] offsets = {{1, 0}, {0, -1}, {-1, 0}, {0, 1}};

    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);

        n = sc.nextInt();

        matrix = new int[n][n];
        candy = new int[n][n];

        LinkedList<Integer> queue = new LinkedList<>();

        for (int i = 0; i < n; i++) {
            for (int j = 0; j < n; j++) {
                candy[i][j] = -1;

                matrix[i][j] = sc.nextInt();
                // 妈妈的位置
                if (matrix[i][j] == -3) {
                    candy[i][j] = 0;
                    queue.add(i * n + j); // 二维坐标一维化
                }
            }
        }

        // 记录题解
        int ans = -1;

        // bfs 按层扩散
        while (!queue.isEmpty()) {
            // 记录当前扩散层的点
            LinkedList<Integer> newQueue = new LinkedList<>();

            // 当前层是否有宝宝所在的点
            boolean flag = false;

            for (int pos : queue) {
                // 源点坐标
                int x = pos / n;
                int y = pos % n;

                // 向四个方向扩散
                for (int[] offset : offsets) {
                    // 当前扩散点坐标
                    int newX = x + offset[0];
                    int newY = y + offset[1];

                    // 当前扩散点坐标越界,或者扩散点是墙,则无法扩散
                    if (newX < 0 || newX >= n || newY < 0 || newY >= n || matrix[newX][newY] == -1) continue;

                    // 当前扩散点坐标对应的糖果数量为-1,说明对应扩散点坐标位置还没有加入到当前扩散层
                    if (candy[newX][newY] == -1) {
                        newQueue.addLast(newX * n + newY); // 加入当前扩散层
                    }

                    // 当前扩散点可能会被多个源点扩散到,因此比较保留扩散过程中带来的较大糖果数
                    // candy[newX][newY] 记录的是当前扩散点获得的糖果数
                    // candy[x][y] + Math.max(0, matrix[newX][newY]) 记录的是从源点(x,y)带来的糖果数 + (newX,newY)位置原本的糖果数
                    candy[newX][newY] =
                            Math.max(candy[newX][newY], candy[x][y] + Math.max(0, matrix[newX][newY]));

                    // 如果当前扩散点是宝宝位置,则可以停止后续层级的bfs扩散,因为已经找到宝宝的最短路径长度(即扩散层数)
                    if (matrix[newX][newY] == -2) {
                        ans = candy[newX][newY];
                        flag = true;
                    }
                }
            }

            // 已经找到去宝宝位置的最短路径和最大糖果数,则终止bfs
            if (flag) break;

            // 否则继续
            queue = newQueue;
        }

        System.out.println(ans);
    }
}

 

Python算法源码
 
def bfs(matrix, n):
    candy = [[-1] * n for _ in range(n)]
    queue = []

    for i in range(n):
        for j in range(n):
            if matrix[i][j] == -3:
                candy[i][j] = 0
                queue.append((i, j))

    directions = ((0, -1), (0, 1), (-1, 0), (1, 0))

    ans = -1

    while len(queue) > 0:
        newQueue = []
        flag = False

        for x, y in queue:
            for offsetX, offsetY in directions:
                newX = x + offsetX
                newY = y + offsetY

                if newX < 0 or newX >= n or newY < 0 or newY >= n or matrix[newX][newY] == -1:
                    continue

                if candy[newX][newY] == -1:
                    newQueue.append((newX, newY))

                candy[newX][newY] = max(candy[newX][newY], candy[x][y] + max(0, matrix[newX][newY]))

                if matrix[newX][newY] == -2:
                    ans = candy[newX][newY]
                    flag = True

        if flag:
            break

        queue = newQueue

    return ans

n = int(input())
matrix = [list(map(int, input().split())) for _ in range(n)]
print(bfs(matrix, n))

C算法源码
#include <stdio.h>
#include <stdlib.h>

#define MAX(a, b) ((a) > (b) ? (a) : (b))

typedef struct ListNode {
    int ele;
    struct ListNode *next;
} ListNode;

typedef struct LinkedList {
    int size;
    ListNode *head;
    ListNode *tail;
} LinkedList;

LinkedList *new_LinkedList() {
    LinkedList *link = (LinkedList *) malloc(sizeof(LinkedList));
    link->size = 0;
    link->head = NULL;
    link->tail = NULL;
    return link;
}

void addLast_LinkedList(LinkedList *link, int ele) {
    ListNode *node = (ListNode *) malloc(sizeof(ListNode));
    node->ele = ele;
    node->next = NULL;

    if (link->size == 0) {
        link->head = node;
        link->tail = node;
    } else {
        link->tail->next = node;
        link->tail = node;
    }

    link->size++;
}

int main() {
    int n;
    scanf("%d", &n);

    int **matrix = (int **) malloc(n * sizeof(int *));
    int **candy = (int **) malloc(n * sizeof(int *));
    for (int i = 0; i < n; i++) {
        matrix[i] = (int *) malloc(n * sizeof(int));
        candy[i] = (int *) malloc(n * sizeof(int));
    }

    LinkedList *queue = new_LinkedList();

    for (int i = 0; i < n; i++) {
        for (int j = 0; j < n; j++) {
            candy[i][j] = -1;
            scanf("%d", &matrix[i][j]);
            if (matrix[i][j] == -3) {
                candy[i][j] = 0;
                addLast_LinkedList(queue, i * n + j);
            }
        }
    }

    int offsets[4][2] = {{-1, 0},
                         {1,  0},
                         {0,  -1},
                         {0,  1}};

    int ans = -1;

    while (queue->size > 0) {
        LinkedList *newQueue = new_LinkedList();
        int flag = 0;

        ListNode *cur = queue->head;
        while (cur != NULL) {
            int x = cur->ele / n;
            int y = cur->ele % n;

            for (int i = 0; i < 4; i++) {
                int newX = x + offsets[i][0];
                int newY = y + offsets[i][1];

                if (newX < 0 || newX >= n || newY < 0 || newY >= n || matrix[newX][newY] == -1) continue;

                if (candy[newX][newY] == -1) {
                    addLast_LinkedList(newQueue, newX * n + newY);
                }

                int remain = MAX(0, matrix[newX][newY]);
                candy[newX][newY] = MAX(candy[newX][newY], candy[x][y] + remain);

                if (matrix[newX][newY] == -2) {
                    ans = candy[newX][newY];
                    flag = 1;
                }
            }

            cur = cur->next;
        }

        if (flag) break;

        queue = newQueue;
    }

    printf("%d\n", ans);

    for (int i = 0; i < n; i++) {
        free(matrix[i]);
        free(candy[i]);
    }
    free(matrix);
    free(candy);
    free(queue);

    return 0;
}

 

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

一剑破天门

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

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

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

打赏作者

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

抵扣说明:

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

余额充值