【华为OD机试 】 最小传输时延Ⅱ(C++ Java JavaScript Python)

339 阅读2分钟

题目描述

有M*N的节点矩阵,每个节点可以向8个方向(上、下、左、右及四个斜线方向)转发数据包,每个节点转发时会消耗固定时延,连续两个相同时延可以减少一个时延值(即当有K个相同时延的节点连续转发时可以减少K- 1个时延值),

求左上角(0,0)开始转发数据包到右下角(M-1,N- 1)并转发出的最短时延。

输入描述

第一行两个数字,M、N,接下来有M行,每行有N个数据,表示M* N的矩阵。

输出描述

最短时延值。

用例

输入3 3
0 2 2
1 2 1
2 2 1
输出3
说明
输入3 3
2 2 2
2 2 2
2 2 2
输出4
说明(2 + 2 + 2 -(3-1))

参考

华为OD机试备考攻略 以及题库目录分值说明 考点说明

C++

#include <iostream>
#include <vector>
#include <unordered_set>
#include <climits>
#include <algorithm>

using namespace std;

int m, n; // 矩阵的行数和列数
vector<vector<int>> matrix; // 存储矩阵的二维向量
vector<vector<int>> offsets = {{-1, 0}, {1, 0}, {0, -1}, {0, 1}, {-1, -1}, {-1, 1}, {1, -1}, {1, 1}}; // 存储八个方向的偏移量

void dfs(int i, int j, int delay, int last, unordered_set<int>& path, vector<int>& res) {
    int cur = matrix[i][j]; // 当前位置的值
    bool flag = cur == last; // 判断是否需要等待一秒
    if (i == m - 1 && j == n - 1) { // 到达终点
        delay += cur - (flag ? 1 : 0); // 更新延迟时间
        res.push_back(delay); // 将当前的延迟时间加入结果向量
        return;
    }
    for (auto& offset : offsets) { // 遍历八个方向
        int new_i = i + offset[0]; // 新的行坐标
        int new_j = j + offset[1]; // 新的列坐标
        int pos = new_i * n + new_j; // 将二维坐标转换为一维坐标
        if (new_i >= 0 && new_i < m && new_j >= 0 && new_j < n && !path.count(pos)) { // 判断新的位置是否越界且是否已经访问过
            path.insert(pos); // 将新的位置加入路径中
            dfs(new_i, new_j, delay + cur - (flag ? 1 : 0), cur, path, res); // 递归遍历新的位置
            path.erase(pos); // 将新的位置从路径中删除,回溯到上一步
        }
    }
}

int main() {
    cin >> m >> n; // 输入矩阵的行数和列数
    matrix.resize(m, vector<int>(n)); // 初始化矩阵的二维向量
    for (int i = 0; i < m; i++) {
        for (int j = 0; j < n; j++) {
            cin >> matrix[i][j]; // 输入矩阵的每个元素
        }
    }
    vector<int> res; // 存储所有到达终点的路径的延迟时间
    unordered_set<int> path; // 存储当前路径中已经访问过的位置
    path.insert(0); // 将起点加入路径中
    dfs(0, 0, 0, INT_MAX, path, res); // 从起点开始遍历矩阵
    cout << *min_element(res.begin(), res.end()) << endl; // 输出所有到达终点的路径中的最小延迟时间
    return 0;
}