引言
今日下午晴,约朋友骑车。绕着梦湖骑了两圈,水波浮动加上一路上下坡,把烦劳都抛掷脑后。回家找青训营刷道算法题,正好找到一道情景相似题
题目:
算法思路
- 首先,题目要每次移动要 连续并且判断是否上下坡变化,然后要找图中能够走过的最大连续数量位置,从某个起点开始的最大连续移动位置想到图里面的DFS ;
- 可以把DFS模版进行修改:增加判断上下坡判断;
算法步骤:
先DFS模板给出,再按题意进行修改
#include <iostream>
#include <vector>
using namespace std;
// 定义方向数组,表示上下左右四个方向
const int dx[] = {-1, 1, 0, 0};
const int dy[] = {0, 0, -1, 1};
// 网格的大小
int n, m;
// 网格数据
vector<vector<int>> grid;
// 访问标记数组
vector<vector<bool>> visited;
// 当前最大连续移动位置的数量
int maxMoves = 0;
// 当前移动次数
int currentMoves = 0;
// DFS 函数
void dfs(int x, int y) {
// 更新最大移动次数
currentMoves++;
maxMoves = max(maxMoves, currentMoves);
// 标记当前节点为已访问
visited[x][y] = true;
// 遍历四个方向
for (int i = 0; i < 4; i++) {
int nx = x + dx[i];
int ny = y + dy[i];
// 检查新位置是否在网格范围内且未被访问
if (nx >= 0 && nx < n && ny >= 0 && ny < m && !visited[nx][ny]) {
dfs(nx, ny);
}
}
// 回溯,恢复当前节点的访问状态
visited[x][y] = false;
currentMoves--;
}
// 主函数
int main() {
// 读取网格大小
cin >> n >> m;
// 初始化网格和访问标记数组
grid.resize(n, vector<int>(m));
visited.resize(n, vector<bool>(m, false));
// 读取网格数据
for (int i = 0; i < n; i++) {
for (int j = 0; j < m; j++) {
cin >> grid[i][j];
}
}
// 从每个位置开始进行 DFS
for (int i = 0; i < n; i++) {
for (int j = 0; j < m; j++) {
dfs(i, j);
}
}
// 输出最大连续移动位置的数量
cout << "最大连续移动位置的数量: " << maxMoves << endl;
return 0;
}
本题完整代码:
#include <iostream>
#include <vector>
#include <algorithm>
#include <functional>
using namespace std;
int solution(int m, int n, vector<vector<int>>& a) {
// 初始化visited数组
vector<vector<bool>> visited(m, vector<bool>(n, false));
// 定义DFS函数
function<int (int,int,bool)> dfs = [&] (int x,int y,bool isUp) -> int {
visited[x][y] = true;//走过
int maxPath = 0;
vector<int> dx = {-1,1,0,0};
vector<int> dy = {0,0,-1,1};
// 遍历四个方向
for(int i=0;i<4;++i) {
int nx = x +dx[i];
int ny = y +dy[i];
// 检查边界
if(nx >=0 && nx <m && ny>=0 && ny<n && !visited[nx][ny]) {
// 是否上下坡
if((isUp && a[nx][ny] < a[x][y]) || (!isUp && a[nx][ny] > a[x][y])) {
// 调用dfs,并且更新maxPath
maxPath = max(maxPath,dfs(nx,ny,!isUp));
}
}
}
// 回溯:标记位置重设为false
visited[x][y] = false;
// 返回路径长度(即当前位置到初始位置)
return maxPath+1;
};
int maxSteps = 0;//步数初始0
// 找初始位置,再使用dfs
for(int i=0;i<n;++i) {
for(int j=0;j<m;++j ){
// isUp 上坡,初始位置上下坡都要选一下试试
// 移动到低位置
maxSteps = max(maxSteps,dfs(i,j,true)) ;
maxSteps = max(maxSteps,dfs(i,j,false));
}
}
// 题目要移动次数,路径减去1
return maxSteps-1;
}
int main() {
vector<vector<int>> a1 = {{1, 2}, {4, 3}};
cout << (solution(2, 2, a1) == 3) << endl;
vector<vector<int>> a2 = {{10, 1, 6}, {5, 9, 3}, {7, 2, 4}};
cout << (solution(3, 3, a2) == 8) << endl;
vector<vector<int>> a3 = {{8, 3, 2, 1}, {4, 7, 6, 5}, {12, 11, 10, 9}, {16, 15, 14, 13}};
cout << (solution(4, 4, a3) == 11) << endl;
}
优化
// dx,dy可以换成pair<int,int>
// 尝试向四个方向移动
vector<pair<int, int>> directions = {{-1, 0}, {1, 0}, {0, -1}, {0, 1}};
for (auto& dir : directions) {
int nx = x + dir.first;
int ny = y + dir.second;
// 检查边界和是否已访问
if (nx >= 0 && nx < m && ny >= 0 && ny < n && !visited[nx][ny]) {
// 检查是否满足上坡或下坡条件
if ((isUp && a[nx][ny] < a[x][y]) || (!isUp && a[nx][ny] > a[x][y])) {
// 递归调用DFS
maxPath = max(maxPath, dfs(nx, ny, !isUp));
}
}
}
多刷题吧,学了数据结构还是要把理论用到实践的,NOI开打