先声明:所提到的代码,都是来自本人学长们的代码,加以本人理解和注释
最优解(不怎么好理解)代码:
(这里要用c++17语言标准,因为这一句:auto [dir_x, dir_y] : dxy。用visual studio编译器的可以自行查找如何设置:https://www.cnblogs.com/xiangsui/p/13928403.html )
#include <bits/stdc++.h>
using namespace std;
int r, c;
int dxy[4][2] = { {-1,0},{1,0},{0,-1},{0,1} };
int dfs(vector<vector<int>>& map, vector<vector<int>>& history, int x, int y)
{
if (history[x][y])return history[x][y]; //如果该点坐标有最优路径,则返回就行,不用再重新找最优路径了
int ans = 0; //这里的ans是指以该x,y坐标出发,所能找到的路径长度,所以每次递归都要清零
for (auto [dir_x, dir_y] : dxy) //遍历偏移量数组
{
int new_x = x + dir_x;
int new_y = y + dir_y;
if (new_x >= 1 && new_x <= r && new_y >= 1 && new_y <= c && map[x][y] > map[new_x][new_y])
{ //先判断下一个坐标合不合法,再去比较坡度大小
ans = max(ans, dfs(map, history, new_x, new_y));//将当前ans与以其他坐标出发找到的路径长度对比,取最大
}
}
return history[x][y] = ans + 1; //将该坐标能找到的最长路径存放在history数组里面(要算上x,y点的长度,所以要ans+1)
}
int main()
{
cin >> r >> c;
vector<vector<int>>map(r + 1, vector<int>(c + 1));
vector<vector<int>>history(r + 1, vector<int>(c + 1));
for (int i = 1; i <= r; i++)
for (int j = 1; j <= c; j++)
cin >> map[i][j];
int ans = 1; //最短路径肯定是1,就是x,y该点
for (int i = 1; i <= r; i++)
for (int j = 1; j <= c; j++)
ans = max(ans, dfs(map, history, i, j)); //将当前最大路径ans与各坐标能找到的最长路径对比,取最大
cout << ans;
return 0;
}
好理解的代码(用时较长)
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <algorithm>
#include <cmath>
using namespace std;
int n, m;
int dir[4][2] = { {1,0},{0,1},{-1,0},{0,-1} }; //偏移量数组
int h[110][110]; //坡度
int lasnum[110][110]; //用来存放从某点走到该坐标的长度
int ans = 0; //最长路径长度
void dfs(int x, int y, int lon)
{
if (lon <= lasnum[x][y]) return; //若从某点走到x,y该点的路径小于从其他点走到x,y的路径,则返回,没必要往下进行了
lasnum[x][y] = lon; //否则从某点走到该坐标的最长路径目前就是lon
for (int i = 0; i < 4; i++)
{
int xx = x + dir[i][0]; //偏移量
int yy = y + dir[i][1]; //偏移量
if (h[x][y] > h[xx][yy] && 1 <= xx && xx <= n && 1 <= yy && yy <= m)
{
dfs(xx, yy, lon + 1); //若坐标合法,则递归,继续走,走过的长度lon+1
}
}
ans = max(ans, lon); //找到目前最长路径ans并存储
}
int main()
{
scanf("%d%d", &n, &m);
for (int i = 1; i <= n; i++)
for (int j = 1; j <= m; j++) scanf("%d", &h[i][j]);
for (int i = 1; i <= n; i++)
for (int j = 1; j <= m; j++) dfs(i, j, 1); //该坐标(点)的长度就是1
printf("%d", ans);
return 0;
}
区别:
比如同样的【3】【3】坐标,最优解代码的那个history【3】【3】数组存放的是该点能找到的最优路径,而好理解的代码的lasnum【3】【3】数组存放的是从某点到该点(3,3)的最长长度。
关于if判断并return返回:
这里耗时短的那个代码,如果【3】【3】坐标已经有最长路径,则不用往下进行了,直接把最长路径返回。
而好理解那个,[3][3]他可能存了某点到(3,3)走过的是长度为5的路径,可是你从某点移动到【3】【3】时,如果路径已经比5还大,这时候,就不能返回,就要往下走去遍历了。
总而言之就是两种代码的重复次数不一样,造成的耗时不同。(如果两种代码都暴力,即把函数开头的if判断并return语句去掉,则耗时都是一模一样的)