华为OD机试真题 新系统 - 直捣黄龙 (C/C++/Py/Java/Js/Go)

直捣黄龙

华为OD机试真题 华为OD上机考试真题 4月8号 200分题型

华为OD机试真题目录点击查看: 华为OD机试真题题库目录|机考题库 + 算法考点详解

题目描述

小王在玩一款叫做直捣黄龙的小游戏,在该游戏中他需要从入口位置进入敌营,绕过哨兵的层层封锁,达到敌军司令部实施斩首行动。

敌军阵营是一个 n∗n 的矩阵,入口在坐标 (0,n/2),敌军司令部在坐标 (n−1,n/2),每个哨兵警戒以自己为中心的9宫格,一旦被哨兵发现则行动失败。同时穿越敌营耗时越长,被发现的概率越高,因此小王需要寻找到可以绕过警戒到达敌军司令部的最短路径。请你设计一个小程序,帮助小王统计这样的路径有多少条,以及路径长度。

规则说明:

  1. 其中 n为大于 1的奇数且取值小于 30 ,坐标 x,y 取值均从 0 开始,敌营左下角定义为 (0,0),右上角定义为 (n−1,n−1)
  2. 敌营入口在坐标 (0,n/2),敌军司令部在坐标 (n−1,n/2)。
  3. 游戏角色的行动方向只包含上、下、左、右四个方向,即一次行动 x、y坐标不可同时变化。
  4. 在没有满足题目要求的可达路径时,需要返回0 0。

输入描述

参数 1,敌军阵营的边长 n 。

参数 2,哨兵位置列表 Point{x,y}x未行坐标,y为列坐标。x和y以逗号分割,不同坐标以空格分割

输出描述

输出两个成员空格分割,第一个成员为最短路径条数,第二个成员为最短路径长度。

用例1

输入

none 复制代码
5
2,2

输出

none 复制代码
2 9

说明

复制代码
两条最短路径,S 表示哨兵位置,A 表示起点,E 表示终点
路径1:[(0,2),(0,1),(0,0),(1,0),(2,0),(3,0),(4,0),(4,1),(4,2)]
路径2:[(0,2),(0,3),(0,4),(1,4),(2,4),(3,4),(4,4),(4,3),(4,2)]
因此返回为2 9

用例2

输入

none 复制代码
3
1,1

输出

none 复制代码
0 0

说明

复制代码
无路径场景,S 表示哨兵位置,A 表示起点,E 表示终点,哨兵警戒了全图

用例3

输入

复制代码
5
2,1

输出

复制代码
1 7

说明

复制代码
单一最短路径场景,S 表示哨兵位置,A表示起点,E表示终点
最短路径:[(0,2),(0,3),(1,3),(2,3),(3,3),(4,3),(4,2)]

题解

思路:BFS

  1. 求最短路径和最短路径方案数,可以借助dist(到达此处最少节点数)distNum(到达此处为最少节点的方案)数组使用BFS进行求解。
  2. 预处理不可访问位置,哨兵位置{x,y}对应九宫格不可访问就是[x-1 - x +1][y-1 - y+1]九个位置不可访问,可以标记为-1
  3. 接下来就是使用BFS算法进行处理,状态转移过程为,当前位置为x, y,扩展到nx,ny
    • 如果nx,ny未访问,则更新 dist[nx][ny] = dist[x][y] + 1, distNum[nx][ny] = distNum[x][y] 并入队
    • 如果nx,ny以访问,并且dist[x][y] + 1 == dist[nx][ny]情况下,说明又找到一条路径,更新distNum[nx][ny] += distNum[x][y]
  4. 按照3逻辑之后,最终判断dist[ex][ey]是否能访问到?不能访问返回{0,0}否则范围对应值即可

额外注意最短路径是访问节点数,所以初始应该设置dist[ex][ey] =1

c++

c++ 复制代码
#include<iostream>
#include<vector>
#include<string>
#include <utility> 
#include <sstream>
#include<algorithm> 
#include<cmath>
#include<map>
#include<climits>
#include <queue>
using namespace std;



struct Point {
   int x;
   int y;
   Point(int xx, int yy) : x(xx), y(yy) {}
};


// 通用 切割函数 函数 将字符串str根据delimiter进行切割
vector<string> split(const string& str, const string& delimiter) {
    vector<string> result;
    size_t start = 0;
    size_t end = str.find(delimiter);
    while (end != string::npos) {
        result.push_back(str.substr(start, end - start));
        start = end + delimiter.length();
        end = str.find(delimiter, start);
    }
    // 添加最后一个部分
    result.push_back(str.substr(start));
    return result;
}


// n大小 points哨兵位置
vector<int> calShortestPath(int n, vector<Point>& points) {
    vector<vector<int>> grid(n, vector<int>(n, 0));
    // 标记不可达位置
    for (Point& point : points) {
        int x = point.x;
        int y = point.y;
        for (int i = x - 1; i <=  x + 1; i++) {
            for (int j = y -1; j <= y + 1; j++) {
                if (i < 0 || i >= n || j < 0 || j >=n) {
                    continue;
                }
                grid[i][j] = -1;
            }
        }
    } 
    int dirs[4][2] = {{1, 0}, {-1, 0}, {0, 1}, {0, -1}};
    
    int sx = 0, sy = n / 2;
    int ex = n - 1, ey = n / 2;
    // 特殊情况判断
    if (grid[sx][sy] == -1 || grid[ex][ey] == -1) {
        return {0, 0};
    }

    
    // dist 记录最少节点数,-1 表示未访问
    vector<vector<int>> dist(n, vector<int>(n, -1));
    // distNum 最少节点数到达次数方案数
    vector<vector<int>> distNum(n, vector<int>(n, 0));
    queue<pair<int, int>> q;
    q.push({sx, sy});
    dist[sx][sy] = 1;
    distNum[sx][sy] = 1;
    while (!q.empty()) {
        auto p = q.front();
        q.pop();
        int x = p.first, y = p.second;
        for (int i = 0; i < 4; i++) {
            int nx = x + dirs[i][0];
            int ny = y + dirs[i][1];
            // 越界或被监控
            if (nx < 0 || nx >= n || ny < 0 || ny >= n || grid[nx][ny] == -1) {
                continue;
            }
            // 初次访问
            if (dist[nx][ny] == -1) {
                // 步数+1
                dist[nx][ny] = dist[x][y]  + 1;
                // 数量相同
               distNum[nx][ny] = distNum[x][y];
               q.push({nx, ny});
            } else if (dist[x][y] + 1 == dist[nx][ny]) {
                 distNum[nx][ny] += distNum[x][y];
            }
        }
    }
    // 不可达
    if (dist[ex][ey] == -1) {
        return {0, 0};
    }
    return {distNum[ex][ey], dist[ex][ey]};
}

int main() {
    int n;
    cin >> n;
    // 吃掉换行
    cin.ignore();
    string line;
    getline(cin, line);
    vector<Point> points;
    for (auto &s : split(line, " ")) {
        vector<string> rowCol = split(s, ",");
        points.push_back({stoi(rowCol[0]), stoi(rowCol[1])});
    }

    vector<int> res = calShortestPath(n, points);
    cout << res[0] << " " << res[1];
    return 0;
}

JAVA

JAVA 复制代码
import java.util.*;

class Point {
    int x, y;
    Point(int xx, int yy) { x = xx; y = yy; }
}

public class Main {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        int n = sc.nextInt();
        sc.nextLine(); // 吃掉换行
        String line = sc.nextLine();
        List<Point> points = new ArrayList<>();
        for (String s : line.split(" ")) {
            String[] rowCol = s.split(",");
            points.add(new Point(Integer.parseInt(rowCol[0]), Integer.parseInt(rowCol[1])));
        }

        int[] res = calShortestPath(n, points);
        System.out.println(res[0] + " " + res[1]);
    }

    static int[] calShortestPath(int n, List<Point> points) {
        int[][] grid = new int[n][n];
        // 标记不可达位置
        for (Point point : points) {
            int x = point.x;
            int y = point.y;
            for (int i = x - 1; i <= x + 1; i++) {
                for (int j = y - 1; j <= y + 1; j++) {
                    if (i < 0 || i >= n || j < 0 || j >= n) continue;
                    grid[i][j] = -1;
                }
            }
        }

        int[][] dirs = {{1,0},{-1,0},{0,1},{0,-1}};
        int sx = 0, sy = n/2;
        int ex = n-1, ey = n/2;

        // 特殊情况判断
        if (grid[sx][sy] == -1 || grid[ex][ey] == -1) return new int[]{0,0};

        // dist 记录节点数,-1 表示未访问
        int[][] dist = new int[n][n];
        // distNum 最少节点数到达次数方案数
        int[][] distNum = new int[n][n];
        for (int[] row : dist) Arrays.fill(row, -1);

        Queue<int[]> q = new LinkedList<>();
        q.offer(new int[]{sx, sy});
        dist[sx][sy] = 1;
        distNum[sx][sy] = 1;

        while (!q.isEmpty()) {
            int[] p = q.poll();
            int x = p[0], y = p[1];
            for (int[] d : dirs) {
                int nx = x + d[0];
                int ny = y + d[1];
                // 越界或被监控
                if (nx < 0 || nx >= n || ny < 0 || ny >= n || grid[nx][ny] == -1) continue;

                // 初次访问
                if (dist[nx][ny] == -1) {
                    dist[nx][ny] = dist[x][y] + 1;
                    // 数量相同
                    distNum[nx][ny] = distNum[x][y];
                    q.offer(new int[]{nx, ny});
                } else if (dist[x][y] + 1 == dist[nx][ny]) {
                    distNum[nx][ny] += distNum[x][y];
                }
            }
        }

        // 不可达
        if (dist[ex][ey] == -1) return new int[]{0,0};
        return new int[]{distNum[ex][ey], dist[ex][ey]};
    }
}

Python

python 复制代码
from collections import deque

n = int(input())
line = input()
points = []
for s in line.split():
    x, y = map(int, s.split(','))
    points.append((x, y))

def calShortestPath(n, points):
    grid = [[0]*n for _ in range(n)]
    # 标记不可达位置
    for x, y in points:
        for i in range(x-1, x+2):
            for j in range(y-1, y+2):
                if 0 <= i < n and 0 <= j < n:
                    grid[i][j] = -1

    dirs = [(1,0),(-1,0),(0,1),(0,-1)]
    sx, sy = 0, n//2
    ex, ey = n-1, n//2

    # 特殊情况判断
    if grid[sx][sy] == -1 or grid[ex][ey] == -1:
        return 0, 0

    # dist 记录最少节点数,-1 表示未访问
    dist = [[-1]*n for _ in range(n)]
    # distNum 最少节点数到达次数方案数
    distNum = [[0]*n for _ in range(n)]

    q = deque()
    q.append((sx, sy))
    dist[sx][sy] = 1
    distNum[sx][sy] = 1

    while q:
        x, y = q.popleft()
        for dx, dy in dirs:
            nx, ny = x+dx, y+dy
            # 越界或被监控
            if 0 <= nx < n and 0 <= ny < n and grid[nx][ny] != -1:
                # 初次访问
                if dist[nx][ny] == -1:
                    dist[nx][ny] = dist[x][y] + 1
                    # 数量相同
                    distNum[nx][ny] = distNum[x][y]
                    q.append((nx, ny))
                # 相同步数,方案累加
                elif dist[x][y] + 1 == dist[nx][ny]:
                    distNum[nx][ny] += distNum[x][y]

    # 不可达
    if dist[ex][ey] == -1:
        return 0, 0
    return distNum[ex][ey], dist[ex][ey]

res = calShortestPath(n, points)
print(res[0], res[1])

JavaScript

js 复制代码
const readline = require('readline');

const rl = readline.createInterface({ input: process.stdin });
let lines = [];

rl.on('line', line => {
    lines.push(line);
}).on('close', () => {
    const n = parseInt(lines[0]);
    const points = [];
    lines[1].split(' ').forEach(s => {
        const [x, y] = s.split(',').map(Number);
        points.push({x, y});
    });

    const res = calShortestPath(n, points);
    console.log(res[0], res[1]);
});

function calShortestPath(n, points) {
    const grid = Array.from({length:n}, () => Array(n).fill(0));
    // 标记不可达位置
    for (const p of points) {
        for (let i = p.x-1; i <= p.x+1; i++) {
            for (let j = p.y-1; j <= p.y+1; j++) {
                if (i>=0 && i<n && j>=0 && j<n) grid[i][j] = -1;
            }
        }
    }

    const dirs = [[1,0],[-1,0],[0,1],[0,-1]];
    const sx = 0, sy = Math.floor(n/2);
    const ex = n-1, ey = Math.floor(n/2);

    // 特殊情况判断
    if (grid[sx][sy] === -1 || grid[ex][ey] === -1) return [0,0];

    const dist = Array.from({length:n}, ()=>Array(n).fill(-1));
    const distNum = Array.from({length:n}, ()=>Array(n).fill(0));

    const q = [[sx, sy]];
    dist[sx][sy] = 1;
    distNum[sx][sy] = 1;

    while (q.length) {
        const [x, y] = q.shift();
        for (const [dx, dy] of dirs) {
            const nx = x+dx, ny = y+dy;
            // 越界或被监控
            if (nx<0||nx>=n||ny<0||ny>=n||grid[nx][ny]==-1) continue;
            // 初次访问
            if (dist[nx][ny]==-1) {
                dist[nx][ny] = dist[x][y]+1;
                distNum[nx][ny] = distNum[x][y];
                q.push([nx, ny]);
            } else if (dist[x][y]+1==dist[nx][ny]) {
                // 相同步数,方案累加
                distNum[nx][ny] += distNum[x][y];
            }
        }
    }

    // 不可达
    if (dist[ex][ey]==-1) return [0,0];
    return [distNum[ex][ey], dist[ex][ey]];
}

Go

go 复制代码
package main

import (
    "bufio"
    "fmt"
    "os"
    "strconv"
    "strings"
)

type Point struct { x, y int }

func main() {
    reader := bufio.NewReader(os.Stdin)
    line1, _ := reader.ReadString('\n')
    n, _ := strconv.Atoi(strings.TrimSpace(line1))
    line2, _ := reader.ReadString('\n')
    line2 = strings.TrimSpace(line2)

    points := []Point{}
    for _, s := range strings.Split(line2, " ") {
        rc := strings.Split(s, ",")
        x, _ := strconv.Atoi(rc[0])
        y, _ := strconv.Atoi(rc[1])
        points = append(points, Point{x, y})
    }

    res := calShortestPath(n, points)
    fmt.Println(res[0], res[1])
}

func calShortestPath(n int, points []Point) [2]int {
    grid := make([][]int, n)
    for i := 0; i < n; i++ { grid[i] = make([]int, n) }

    // 标记不可达位置
    for _, p := range points {
        for i := p.x-1; i <= p.x+1; i++ {
            for j := p.y-1; j <= p.y+1; j++ {
                if i>=0 && i<n && j>=0 && j<n {
                    grid[i][j] = -1
                }
            }
        }
    }

    dirs := [][2]int{{1,0},{-1,0},{0,1},{0,-1}}
    sx, sy := 0, n/2
    ex, ey := n-1, n/2

    // 特殊情况判断
    if grid[sx][sy]==-1 || grid[ex][ey]==-1 { return [2]int{0,0} }

    dist := make([][]int, n)
    distNum := make([][]int, n)
    for i := 0; i < n; i++ {
        dist[i] = make([]int, n)
        distNum[i] = make([]int, n)
        for j := 0; j < n; j++ { dist[i][j] = -1 }
    }

    queue := [][2]int{{sx, sy}}
    dist[sx][sy] = 1
    distNum[sx][sy] = 1

    for len(queue) > 0 {
        cur := queue[0]; queue = queue[1:]
        x, y := cur[0], cur[1]
        for _, d := range dirs {
            nx, ny := x+d[0], y+d[1]
            // 越界或被监控
            if nx<0 || nx>=n || ny<0 || ny>=n || grid[nx][ny]==-1 { continue }
            // 初次访问
            if dist[nx][ny]==-1 {
                dist[nx][ny] = dist[x][y]+1
                distNum[nx][ny] = distNum[x][y]
                queue = append(queue, [2]int{nx, ny})
            } else if dist[x][y]+1 == dist[nx][ny] {
                // 相同步数,方案累加
                distNum[nx][ny] += distNum[x][y]
            }
        }
    }

    // 不可达
    if dist[ex][ey]==-1 { return [2]int{0,0} }
    return [2]int{distNum[ex][ey], dist[ex][ey]}
}

C语言

cpp 复制代码
#include <stdio.h>
#include <string.h>
#include <stdlib.h>

typedef struct { int x, y; } Point;

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

    char line[10000];
    fgets(line, sizeof(line), stdin);

    Point points[500];
    int pointCount = 0;

    // 通用切割,根据空格分割坐标点
    char *token = strtok(line, " \n");
    while (token) {
        int x, y;
        sscanf(token, "%d,%d", &x, &y);
        points[pointCount++] = (Point){x, y};
        token = strtok(NULL, " \n");
    }

    int grid[50][50] = {0};
    // 标记不可达位置
    for (int k=0; k<pointCount; k++) {
        int x = points[k].x, y = points[k].y;
        for (int i=x-1;i<=x+1;i++)
            for (int j=y-1;j<=y+1;j++)
                if (i>=0 && i<n && j>=0 && j<n)
                    grid[i][j] = -1;
    }

    int dirs[4][2] = {{1,0},{-1,0},{0,1},{0,-1}};
    int sx=0, sy=n/2, ex=n-1, ey=n/2;

    // 特殊情况判断
    if (grid[sx][sy]==-1 || grid[ex][ey]==-1) { printf("0 0\n"); return 0; }

    int dist[50][50], distNum[50][50];
    for(int i=0;i<n;i++)
        for(int j=0;j<n;j++){ dist[i][j]=-1; distNum[i][j]=0; }

    typedef struct { int x, y; } Node;
    Node queue[2500]; int head=0, tail=0;
    queue[tail++] = (Node){sx, sy};
    dist[sx][sy] = 1;
    distNum[sx][sy] = 1;

    while(head<tail){
        Node cur = queue[head++];
        int x=cur.x, y=cur.y;
        for(int d=0; d<4; d++){
            int nx=x+dirs[d][0], ny=y+dirs[d][1];
            // 越界或被监控
            if(nx<0||nx>=n||ny<0||ny>=n||grid[nx][ny]==-1) continue;
            // 初次访问
            if(dist[nx][ny]==-1){
                dist[nx][ny] = dist[x][y]+1;
                distNum[nx][ny] = distNum[x][y];
                queue[tail++] = (Node){nx, ny};
            } else if(dist[x][y]+1==dist[nx][ny]){
                // 相同步数,方案累加
                distNum[nx][ny] += distNum[x][y];
            }
        }
    }

    // 不可达
    if(dist[ex][ey]==-1) printf("0 0\n");
    else printf("%d %d\n", distNum[ex][ey], dist[ex][ey]);

    return 0;
}
相关推荐
无限码力2 天前
华为OD技术面真题 - JAVA开发- spring框架 - 7
java·开发语言·华为od·华为od面试真题·华为odjava八股文·华为odjava开发题目·华为odjava开发高频题目
无限码力16 天前
华为OD机试双机位C卷真题-红黑图(C/C++/Py/Java/Js/Go)
华为od·华为od机试真题·华为od机试双机位c卷·华为od上机考试真题·华为od机考真题·华为od机试-红黑图·华为od机考真题-红黑图
无限码力16 天前
华为OD机试双机位C卷-用户入网定期复评(C/C++/Py/Java/Js/Go)
华为od·华为od机试真题·华为od机试双机位c卷·华为od上机考试真题·华为od机考真题·华为od-用户入网定期复评
gis分享者17 天前
华为OD面试-Java、C++、Pyhton等多语言实现-目录
java·c++·华为od·面试·目录·od·机试
无限码力18 天前
华为OD机试双机位C卷-虚拟文件系统(C/C++/Py/Java/Js/Go)
华为od·华为od机试真题·华为od机试双机位c卷·华为od上机考试真题·华为od机考真题·华为od-虚拟文件系统·华为od机试题库
sprite_雪碧20 天前
考研机试笔记-1输入输出
笔记·考研·华为od
无限码力24 天前
华为OD机试真题2026双机位C卷 C++实现【日志解析】
c++·华为od·华为od机试真题·华为od机考真题·华为od机试真题-日志解析
uesowys1 个月前
华为OD算法开发指导-数据结构-图
数据结构·算法·华为od
快敲啊死鬼1 个月前
机试day5
算法·华为od·华为