题目描述
给定一个 m*n 的整数矩阵作为地图,矩阵数值为地形高度。中庸行者选择地图中的任意一点作为起点,尝试往上、下、左、右四个相邻格子移动,移动时有如下约束:
-
中庸行者只能上坡或者下坡,不能走到高度相同的点
-
不允许连续上坡或者连续下坡,需要交替进行
-
每个位置只能经过一次,不能重复行走 请给出中庸行者在本地图内,能连续移动的最大次数
输入描述
第一行两个数字,分别为行数和每行的列数;
后续数据为矩阵地图内容 矩阵边长范围 1-8,地形高度范围 0-100000
输出描述
一个整数,代表中庸行者在本地图内,能连续移动的最大次数
问题分析
这是一个典型的图搜索问题,需要在二维网格中寻找满足特定条件的最长路径。问题的难点在于:
-
路径不能有环:不能重复访问同一个格子
-
趋势必须交替:上升和下降必须严格交替
-
需要全局最优:要从所有可能的起点中找到最长路径
解题思路
核心思想:DFS + 回溯
我们采用深度优先搜索(DFS)结合回溯的方法来解决这个问题:
-
遍历所有起点:由于最长路径可能从任意格子开始,我们需要尝试所有起点
-
DFS递归搜索:从当前格子出发,尝试所有可能的下一步
-
状态维护:
-
visited数组:记录当前路径已经访问过的格子,防止形成环路 -
mode参数:记录上一步的趋势(0:初始,1:上升,-1:下降)
-
-
回溯机制:搜索完一个分支后,撤销当前格子的访问标记,以便尝试其他路径
算法步骤
-
读取输入的网格大小和高度值
-
初始化访问标记数组
visited -
对于每个格子作为起点:
-
调用DFS函数进行深度优先搜索
-
更新全局最大步数
maxSteps
-
-
输出最大步数
完整代码实现
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)