【算法】深度优先搜索实例:华为OD机考双机位A卷- 中庸行者

题目描述

给定一个 m*n 的整数矩阵作为地图,矩阵数值为地形高度。中庸行者选择地图中的任意一点作为起点,尝试往上、下、左、右四个相邻格子移动,移动时有如下约束:

  • 中庸行者只能上坡或者下坡,不能走到高度相同的点

  • 不允许连续上坡或者连续下坡,需要交替进行

  • 每个位置只能经过一次,不能重复行走 请给出中庸行者在本地图内,能连续移动的最大次数

输入描述

第一行两个数字,分别为行数和每行的列数;

后续数据为矩阵地图内容 矩阵边长范围 1-8,地形高度范围 0-100000

输出描述

一个整数,代表中庸行者在本地图内,能连续移动的最大次数


问题分析

这是一个典型的图搜索问题,需要在二维网格中寻找满足特定条件的最长路径。问题的难点在于:

  1. 路径不能有环:不能重复访问同一个格子

  2. 趋势必须交替:上升和下降必须严格交替

  3. 需要全局最优:要从所有可能的起点中找到最长路径

解题思路

核心思想:DFS + 回溯

我们采用深度优先搜索(DFS)结合回溯的方法来解决这个问题:

  1. 遍历所有起点:由于最长路径可能从任意格子开始,我们需要尝试所有起点

  2. DFS递归搜索:从当前格子出发,尝试所有可能的下一步

  3. 状态维护

    • visited数组:记录当前路径已经访问过的格子,防止形成环路

    • mode参数:记录上一步的趋势(0:初始,1:上升,-1:下降)

  4. 回溯机制:搜索完一个分支后,撤销当前格子的访问标记,以便尝试其他路径

算法步骤

  1. 读取输入的网格大小和高度值

  2. 初始化访问标记数组visited

  3. 对于每个格子作为起点:

    • 调用DFS函数进行深度优先搜索

    • 更新全局最大步数maxSteps

  4. 输出最大步数

完整代码实现

cpp 复制代码
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;

/**
 * 深度优先搜索函数,用于寻找从当前位置开始的最长交替路径
 * 
 * @param map 二维网格地图,存储每个位置的高度值
 * @param visited 访问标记数组,记录哪些位置已被当前路径访问过
 * @param maxSteps 引用参数,记录全局最大步数(最长路径长度)
 * @param x 当前位置的行坐标
 * @param y 当前位置的列坐标
 * @param steps 当前路径已走的步数
 * @param mode 当前趋势模式:0表示起始点(无趋势),1表示上一步为上升趋势,-1表示上一步为下降趋势
 */
void dfs(const vector<vector<int>>& map, vector<vector<bool>>& visited, 
         int& maxSteps, int x, int y, int steps, int mode) {
    // 标记当前位置为已访问,避免路径中重复访问同一位置
    visited[x][y] = true;
    
    // 更新全局最大步数:取当前步数与已记录最大步数中的较大值
    maxSteps = max(maxSteps, steps);

    // 定义四个移动方向:右、左、下、上
    vector<vector<int>> dirs = {{0, 1}, {0, -1}, {1, 0}, {-1, 0}};

    // 遍历所有可能的移动方向
    for (auto& dir : dirs) {
        // 计算下一个位置的坐标
        int nx = x + dir[0];
        int ny = y + dir[1];

        // 边界检查:确保下一个位置在网格范围内
        // 访问检查:确保下一个位置未被当前路径访问过
        if (nx < 0 || ny < 0 || nx >= map.size() || ny >= map[0].size() || visited[nx][ny]) continue;

        // 计算高度差:下一个位置与当前位置的高度差值
        int diff = map[nx][ny] - map[x][y];
        
        // 高度相同的位置不能成为路径的一部分(题目要求)
        if (diff == 0) continue;

        // 根据当前趋势模式选择下一个位置
        if (mode == 0) {
            // 起始点情况:可以选择任意趋势
            // diff > 0 表示上升趋势,否则为下降趋势
            dfs(map, visited, maxSteps, nx, ny, steps + 1, diff > 0 ? 1 : -1);
        } else if (mode == 1 && diff < 0) {
            // 当前为上升趋势,下一个必须为下降趋势(diff < 0)
            dfs(map, visited, maxSteps, nx, ny, steps + 1, -1);
        } else if (mode == -1 && diff > 0) {
            // 当前为下降趋势,下一个必须为上升趋势(diff > 0)
            dfs(map, visited, maxSteps, nx, ny, steps + 1, 1);
        }
        // 其他情况:趋势不符合交替要求,不进行递归
    }

    // 回溯:取消当前位置的访问标记
    // 允许其他路径访问该位置(因为一条路径不能重复访问同一位置,但不同路径可以)
    visited[x][y] = false;
}

/**
 * 主函数:程序入口点
 * 1. 读取输入数据(网格大小和高度值)
 * 2. 初始化数据结构
 * 3. 对每个起始点执行DFS搜索
 * 4. 输出最长交替路径的步数
 */
int main() {
    int rows, cols;  // 网格的行数和列数
    cin >> rows >> cols;  // 读取行数和列数
    
    // 初始化地图数据结构:创建一个rows行cols列的二维向量,存储高度值
    vector<vector<int>> map(rows, vector<int>(cols));
    
    // 初始化访问标记数组:创建一个rows行cols列的二维向量,所有元素初始化为false
    // 用于在DFS过程中跟踪哪些位置已被当前路径访问
    vector<vector<bool>> visited(rows, vector<bool>(cols, false));

    // 读取地图数据:填充网格的高度值
    for (int i = 0; i < rows; i++) {
        for (int j = 0; j < cols; j++) {
            cin >> map[i][j];  // 读取每个位置的高度值
        }
    }

    int maxSteps = 0;  // 全局最长路径步数,初始化为0
    
    // 从每个点作为起始点开始DFS搜索
    for (int i = 0; i < rows; i++) {
        for (int j = 0; j < cols; j++) {
            // 以(i, j)为起点,初始步数为0,模式为0(起始点)
            dfs(map, visited, maxSteps, i, j, 0, 0);
        }
    }

    // 输出结果:最长交替路径的步数
    cout << maxSteps << endl;
    
    return 0;  // 程序正常结束
}

时间复杂度分析

  • 对于每个起点,DFS的时间复杂度最坏为O(4^L),其中L是路径长度

  • 共有M×N个起点,总时间复杂度约为O(M×N×4^L)

  • 在实际测试中,由于回溯剪枝(高度不能相同、趋势必须交替),实际搜索空间会大大减少

空间复杂度分析

  • 存储网格:O(M×N)

  • 访问标记数组:O(M×N)

  • 递归栈深度:O(L),其中L是最长路径长度

  • 总空间复杂度:O(M×N + L)

相关推荐
a3535413822 小时前
参数化曲线弧长公式推导
算法
不知名XL2 小时前
day27 贪心算法 part05
算法·贪心算法
Tisfy2 小时前
LeetCode 3047.求交集区域内的最大正方形面积:2层循环暴力枚举
算法·leetcode·题解·模拟·枚举·几何
云深麋鹿2 小时前
C++入门篇
c++
量子炒饭大师2 小时前
【C++入门】零域终端的虚空指针协议——【nullptr】还在为编译器给NULL匹配为int而头疼?nullptr给予你全新的字面量!
开发语言·c++·nullptr
阿豪只会阿巴3 小时前
【多喝热水系列】从零开始的ROS2之旅——Day10 话题的订阅与发布1:Python
开发语言·c++·python·ubuntu·ros2
junziruruo3 小时前
t-SNE可视化降维技术(以FMTrack频率感知与多专家融合文章中的内容为例)
人工智能·算法
羊小猪~~3 小时前
【QT】--文件操作
前端·数据库·c++·后端·qt·qt6.3
藦卡机器人3 小时前
自动焊接机器人的核心技术要求与标准
人工智能·算法·机器人