P1434 [SHOI2002] 滑雪

先声明:所提到的代码,都是来自本人学长们的代码,加以本人理解和注释


 

 

最优解(不怎么好理解)代码:

(这里要用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语句去掉,则耗时都是一模一样的)

  • 5
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值