华为OD机试—亲子游戏(C++)

目录

题目描述

输入描述

输出描述

为什么刷华为OD机试题?

思路

1. 输入处理与初始化

2. 核心数据结构

3. BFS 搜索过程(核心逻辑)

初始化起点:

循环处理队列中的位置:

4. 输出结果

代码


题目描述

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

    妈妈必须在最短时间(每单位时间走一步)到达宝宝的位置,只能上下左右移动,不能走障碍物。
    移动过程中经过的格子糖果可以全部拿走。
    优先保证最短时间到达,其次在最短路径中尽可能多拿糖果。

输入描述

    第一行输入矩阵大小N(最大50×50)。
    之后N行,每行N个整数,表示格子属性:
        -3:妈妈
        -2:宝宝
        -1:障碍
        ≥0:糖果数(0表示无糖果但可通行)。

输出描述

输出妈妈在最短时间内到达宝宝位置时能拿到的最大糖果数;若无法到达,输出-1。

示例
输入:

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

输出:

9  

解释:两条最短路径(6步),其中一条路径糖果总和为9。

为什么刷华为OD机试题?

        华为OD(Outsourcing Dispacth)是华为与外企德科联合招聘的精英外包模式,员工由德科签订合同并派驻华为工作。

        OD员工工作内容、管理方式与华为正式员工高度对齐,同工同酬,如:工作内容、福利(如五险一金、加班费、夜宵补贴等)基本一致;

        且有机会通过绩效考核转为正式员工(需入职满1年、两次绩效A并通过可信认证考试)。

    与传统外包的区别:
        薪资对标:D1-D5等级对应华为13-17级,月薪范围9k-29k,年终奖2-4个月(绩效A可拿满)。
        发展路径:参与核心项目开发,与华为员工共用技术晋升通道,转正后享股票分红(需职级≥15级)。

        华为OD机试是华为对外包岗位选拔人才的核心环节,为在线编程考试,主要考察算法设计、数据结构、代码调试能力。是入职流程中的核心环节,直接影响后续面试资格和薪资定级;

        据统计,机试通过率约75%,非目标院校需300+分(目标院校150+分),未通过需等待半年冷冻期。

        题目构成:

        3道编程题:2道100分题(逻辑分析/字符串处理)+1道200分题(动态规划/图论等),总分400分,难度分布为简单+简单+中等/困难。

        考试时间:150分钟,支持本地IDE编码后复制提交,但需注意代码重复率(>80%可能判作弊)。

        题库特点:

        根据历史记录,华为OD面试的考卷每季度(Q1-Q4)更换一次算法考试题目:旧题(占比66%)+新题(占比33%),抽中原题概率约80%。

        查重机制:代码相似度超80%判作弊,建议修改变量名、调整逻辑顺序。

        评分标准:按测试用例通过比例得分,非目标院校需≥300分,目标院校≥150分即可; 

思路

核心逻辑是使用 BFS(广度优先搜索)在网格中寻找从起点到终点的最短路径,并在所有最短路径中收集最多的糖果,最终输出最大糖果数(若无法到达终点则输出 - 1)。以下是详细逻辑拆解:

1. 输入处理与初始化

  • 读取网格规模:首先读取整数n,表示网格是n×n的二维数组。
  • 读取网格数据:通过双重循环读取n×n的网格数据到vec中,同时记录:
    • 起点坐标(startx, starty):网格中值为-3的位置(代表起点)。
    • 终点坐标(endx, endy):网格中值为-2的位置(代表终点)。
  • 方向数组disXdisY分别存储 x 轴和 y 轴的偏移量,对应 “上、右、下、左” 四个方向(用于遍历相邻单元格)。

2. 核心数据结构

  • 队列q:BFS 的核心容器,用于按顺序存储待处理的网格坐标(保证 “先处理近距离位置”)。
  • 距离数组distdist[i][j]记录从起点到(i,j)最短步数,初始值为INT_MAX(表示 “尚未到达”)。
  • 糖果数组maxcandymaxcandy[i][j]记录在 “最短步数” 前提下,到达(i,j)时能收集的最大糖果数,初始值为-1(表示 “未收集到糖果”)。

3. BFS 搜索过程(核心逻辑)

BFS 的本质是 “按距离分层扩散”,确保首次到达某位置时的步数为最短路径。这里额外处理了 “相同步数下最大化糖果数” 的需求。

初始化起点:
  • 起点的最短距离dist[startx][starty]设为0(距离自己 0 步)。
  • 起点的初始糖果数maxcandy[startx][starty]设为0(尚未收集任何糖果)。
  • 将起点坐标(startx, starty)加入队列,开始 BFS。
循环处理队列中的位置:
  1. 取出队首位置:获取当前处理的坐标(x,y),并弹出队列。
  2. 获取当前状态:记录当前位置的最短距离curDist和最大糖果数curCandy
  3. 遍历四个方向的邻居:通过方向数组计算邻居坐标(dx, dy)dx = x + disX[i]dy = y + disY[i])。
  4. 有效性检查
    • 边界检查:dxdy必须在[0, n-1]范围内(不超出网格)。
    • 障碍物检查:若vec[dx][dy] == -1(障碍物),则跳过该邻居。
  5. 计算新状态
    • 新距离newDist:当前距离 + 1(移动一步到邻居)。
    • 新糖果数newCandy:当前糖果数 + 邻居位置的糖果(若邻居有糖果,即vec[dx][dy] > 0)。
  6. 更新状态并入队
    • newDist < dist[dx][dy]:找到更短的路径,更新dist[dx][dy]newDistmaxcandy[dx][dy]newCandy,并将(dx, dy)入队(继续扩散)。
    • newDist == dist[dx][dy]newCandy > maxcandy[dx][dy]:路径长度相同,但能收集更多糖果,更新maxcandy[dx][dy]newCandy,并将(dx, dy)入队(其邻居可能因糖果数更新而受益)。

4. 输出结果

  • dist[endx][endy] != INT_MAX:说明终点可达,输出终点的最大糖果数maxcandy[endx][endy]
  • 否则:终点不可达,输出-1

代码

#include<iostream>
#include<vector>
#include<queue>
using namespace std;
int main() {
    int n; cin >> n;
    vector<vector<int>> vec(n, vector<int>(n));
    int startx, starty,endx,endy;
    for (int i = 0; i < n;i++) {
        for (int j = 0; j < n; j++) {
            cin >> vec[i][j];
            if (vec[i][j] == -3) {
                startx = i;
                starty = j;
            }
            if (vec[i][j] == -2) {
                endx = i;
                endy = j;
            }
        }
    }
    //上右下左
    int disX[4] = { -1,0,1,0 };
    int disY[4] = { 0,1,0,-1 };
    queue<pair<int, int>> q;
    q.push({startx, starty});
    vector<vector<int>> dist(n, vector<int>(n,INT_MAX));
    vector<vector<int>> maxcandy(n, vector<int>(n, -1));
    dist[startx][starty] = 0;
    maxcandy[startx][starty] = 0;
    while (!q.empty()) {
        int x= q.front().first;
        int y = q.front().second;
        q.pop();
        int curCandy = maxcandy[x][y];
        int curDist = dist[x][y];
        for (int i = 0; i < 4; i++) {
            int dx = x + disX[i];
            int dy = y + disY[i];
            if (dx < 0 || dy < 0 || dx >= n || dy >= n)continue;
            if (vec[dx][dy] == -1)continue;
            int newDist = curDist + 1;
            int newCandy = curCandy;
            if (vec[dx][dy] > 0) {
                newCandy += vec[dx][dy];
            }
            if (newDist < dist[dx][dy]) {
                dist[dx][dy] = newDist;
                maxcandy[dx][dy] = newCandy;
                q.push({ dx,dy });
            }else if (newDist == dist[dx][dy]&&newCandy> curCandy) {
                maxcandy[dx][dy] = newCandy;
                q.push({ dx,dy });
            }
        }
    }
    if (dist[endx][endy] != INT_MAX)cout << maxcandy[endx][endy];
    else cout << -1;
    return 0;
}

对您有帮助的话,可以点个免费的赞吗~

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值