OD统一考试(C卷)
分值: 200分
题解: Java / Python / C++

题目描述
评估一个网络的信号质量,其中一个做法是将网络划分为栅格,然后对每个栅格的信号质量计算。
路测的时候,希望选择一条信号最好的路线(彼此相连的栅格集合)进行演示。现给出 R 行 C 列的整数数组 Cov ,每个单元格的数值 S 即为该栅格的信号质量(已归一化,无单位,值越大信号越好)。
要求从 [0,0] 到 [R−1,C−1] 设计一条最优路测路线。返回该路线得分。
规则:
- 路测路线可以 上下左右四个方向,不能对角。
 - 路线的评分是以路线上信号最差的栅格为准的。例如路径 8→4→5→9 的值为 4 ,该线路评分为 4 。线路最优表示该条线路的评分最高。
 
输入描述
第一行表示栅格的行数 R;
第二行表示栅格的列数 C;
第三行开始,每一行表示栅格地图一行的信号值,每个单元格的数值为 S 。
- 1≤R,C≤20
 - 1≤S≤65535
 
输出描述
最优路线的得分。
示例1
输入:
3
3
5 4 5
1 2 6
7 4 6
输出:
4
说明:
路线为: 5→4→5→6→6 。
 
示例2
输入:
6
5
3 4 6 3 4
0 2 1 1 7
8 8 3 2 7
3 2 4 9 8
4 1 2 0 0
4 6 5 4 3
输出:
3
说明:
路线为: 3→4→6→3→4→7→7→8→9→4→3→8→8→3→4→4→6→5→4→3 。
 
题解
该题目属于搜索算法的一种,通过搜索找到最优路径。首先,对于每个栅格,其数值
S表示信号质量。我们需要从栅格[0,0]出发,沿着上下左右四个方向,选择信号最优的路径到达[R-1,C-1]。为了找到最优路径,可以采用二分搜索的方式,不断调整路径信号的评分限制,直到找到最优路径。在搜索路径的过程中,需要使用队列或栈等数据结构来保存当前搜索的状态。
Java
import java.util.ArrayDeque;
import java.util.Queue;
import java.util.Scanner;
/**
 * @author code5bug
 */
public class Main {
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        int R = scanner.nextInt(), C = scanner.nextInt();
        int[][] cov = new int[R][C];
        for (int i = 0; i < R; i++) {
            for (int j = 0; j < C; j++) {
                cov[i][j] = scanner.nextInt();
            }
        }
        int l = 1, r = 65535 + 1;
        while (l + 1 < r) {
            int m = (l + r) >> 1;
            if (ok(R, C, cov, m)) {
                l = m;
            } else {
                r = m;
            }
        }
        System.out.println(l);
    }
    // 条线路的评分 limit 能否从 (0,0) 到达 (R-1, C-1)
    private static boolean ok(int R, int C, int[][] cov, int limit) {
        boolean[][] vis = new boolean[R][C];
        int[][] directions = {{0, 1}, {1, 0}, {0, -1}, {-1, 0}};
        // 初始化队列,起点为 (0, 0)
        Queue<int[]> queue = new ArrayDeque<>();
        queue.offer(new int[]{0, 0});
        while (!queue.isEmpty()) {
            int[] current = queue.poll();
            int r = current[0], c = current[1];
            if (cov[r][c] < limit) continue;   // 信号质量不够,跳过
            vis[r][c] = true;
            // 遍历四个方向
            for (int[] direction : directions) {
                int nr = r + direction[0], nc = c + direction[1];
                if (0 <= nr && nr < R && 0 <= nc && nc < C && !vis[nr][nc]) {
                    queue.offer(new int[]{nr, nc});
                }
            }
        }
        return vis[R - 1][C - 1];
    }
}
 
Python
R, C = int(input()), int(input())
cov = [list(map(int, input().split())) for _ in range(R)]
def ok(limit: int) -> bool:
    """ 条线路的评分 limit 能否从 (0,0) 到达 (R-1, C-1) """
    global R, C, cov
    vis = [[False] * C for _ in range(R)]
    q = [(0, 0)]
    while q:
        r, c = q.pop()
        if cov[r][c] < limit:  # 信号质量不够,跳过
            continue
        vis[r][c] = True
        for dr, dc in [(0, 1), (1, 0), (0, -1), (-1, 0)]:  # 上下左右四个位置
            nr, nc = r + dr, c + dc
            if 0 <= nr < R and 0 <= nc < C and not vis[nr][nc]:
                q.append((nr, nc))
    return vis[R-1][C-1]
l, r = 1, 65535 + 1
while l + 1 < r:
    m = (l + r) >> 1
    if ok(m):
        l = m
    else:
        r = m
print(l)
 
C++
#include <iostream>
#include <vector>
#include <stack>
using namespace std;
int main() {
    int R, C;
    cin >> R >> C;
    // 读取输入矩阵
    vector<vector<int>> cov(R, vector<int>(C));
    for (int i = 0; i < R; ++i) {
        for (int j = 0; j < C; ++j) {
            cin >> cov[i][j];
        }
    }
    // 定义函数 ok
    auto ok = [&](int limit) -> bool {
        vector<vector<bool>> vis(R, vector<bool>(C, false));
        stack<pair<int, int>> q;
        q.push({0, 0});
        while (!q.empty()) {
            int r = q.top().first;
            int c = q.top().second;
            q.pop();
            if (cov[r][c] < limit) {
                continue;  // 信号质量不够,跳过
            }
            vis[r][c] = true;
            // 遍历四个方向
            vector<pair<int, int>> directions = {{0, 1}, {1, 0}, {0, -1}, {-1, 0}};
            for (const auto& direction : directions) {
                int nr = r + direction.first;
                int nc = c + direction.second;
                if (0 <= nr && nr < R && 0 <= nc && nc < C && !vis[nr][nc]) {
                    q.push({nr, nc});
                }
            }
        }
        return vis[R-1][C-1];
    };
    // 二分搜索
    int l = 1, r = 65535 + 1;
    while (l + 1 < r) {
        int m = (l + r) >> 1;
        if (ok(m)) {
            l = m;
        } else {
            r = m;
        }
    }
    cout << l << endl;
    return 0;
}
 
❤️华为OD机试面试交流群(每日真题分享): 加V时备注“华为od加群”
🙏整理题解不易, 如果有帮助到您,请给点个赞 ❤️ 和收藏 ⭐,让更多的人看到。🙏🙏🙏
![[leetcode] 33. 搜索旋转排序数组](https://img-blog.csdnimg.cn/direct/a36c1b59f2eb48eebd27dc7ba26116ca.png)


















