算法提高 最长滑雪道(动态规划 + Dfs)

试题 算法提高 最长滑雪道

资源限制
时间限制:1.0s 内存限制:256.0MB
问题描述
  小袁非常喜欢滑雪, 因为滑雪很刺激。为了获得速度,滑的区域必须向下倾斜,而且当你滑到坡底,你不得不再次走上坡或者等待升降机来载你。 小袁想知道在某个区域中最长的一个滑坡。区域由一个二维数组给出。数组的每个数字代表点的高度。如下:
  一个人可以从某个点滑向上下左右相邻四个点之一,当且仅当高度减小。在上面的例子中,一条可滑行的滑坡为24-17-16-1。当然25-24-23-…-3-2-1更长。事实上,这是最长的一条。
  你的任务就是找到最长的一条滑坡,并且将滑坡的长度输出。 滑坡的长度定义为经过点的个数,例如滑坡24-17-16-1的长度是4。
输入格式
  输入的第一行表示区域的行数R和列数C(1<=R, C<=10)。下面是R行,每行有C个整数,依次是每个点的高度h(0<= h <=10000)。
输出格式
  只有一行,为一个整数,即最长区域的长度。
样例输入
5 5
1 2 3 4 5
16 17 18 19 6
15 24 25 20 7
14 23 22 21 8
13 12 11 10 9
样例输出
25


题解

这题可以用动态规划的思想来做,因为图中的某点(a)能滑的最大的格子数是一个定值,无论其之前是怎么到达这里的,好好体会,因为之前到达它的格子(b)必定比它高,而这个格子 a 往下能滑到的格子必定不包括 b 。这样就可以用记忆化搜索来解决这题。
所以只要:

状态: dp[r][c] 第r行第c列格子为起点最大能滑的格子数
状态转移:
	for (int i = 0; i < 4; i++)		//取四个方向最大的(当然还要判断是否可走)
			dp[r][c]=max(dp[r][c],dfs(newr, newc)+1);

AC代码如下:

//最长滑雪道
//蓝桥杯 算法提高 ADV-294
#include<iostream>
#include<algorithm>
using namespace std;

const int maxn = 10 + 2;
int graph[maxn][maxn];
int dp[maxn][maxn];
int row, col;
const int nnext[4][2] = { {0,1},{1,0},{0,-1},{-1,0} };		//行走的方向

bool check(int newr,int newc, int r, int c){				//判断是否合法
	if (newr >= 0 && newr < row && newc >= 0 && newc < col)	//判断是否超出界限
		if (graph[r][c] > graph[newr][newc])				//判断高度是否符合要求
			return true;
	return false;
}

int dfs(int r,int c){
	int newr, newc;
	
	if(dp[r][c]!=-1)	//之前访问过
		return dp[r][c];
	
	dp[r][c]=1;
	for (int i = 0; i < 4; i++){
		newr = r + nnext[i][0];
		newc = c + nnext[i][1];
		if (check(newr, newc, r, c))
			dp[r][c]=max(dp[r][c],dfs(newr, newc)+1);
	}
	return dp[r][c];
}

int main(){
	int max_length=0;
	cin >> row >> col;
	for (int i = 0; i < row; i++)
		for (int j = 0; j < col; j++){
			cin >> graph[i][j];
			dp[i][j]=-1;
		}
			
	for (int i = 0; i < row; i++)	
		for (int j = 0; j < col; j++)
			max_length=max(max_length,dfs(i,j));
			
	cout << max_length << endl;
	return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值