【C++】1088:滑雪(动规/递推)

1088:滑雪

总时间限制: 1000ms 内存限制: 65536kB

描述
Michael喜欢滑雪百这并不奇怪, 因为滑雪的确很刺激。可是为了获得速度,滑的区域必须向下倾斜,而且当你滑到坡底,你不得不再次走上坡或者等待升降机来载你。Michael想知道载一个区域中最长的滑坡。区域由一个二维数组给出。数组的每个数字代表点的高度。下面是一个例子
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

一个人可以从某个点滑向上下左右相邻四个点之一,当且仅当高度减小。在上面的例子中,一条可滑行的滑坡为24-17-16-1。当然25-24-23-…-3-2-1更长。事实上,这是最长的一条。

输入
输入的第一行表示区域的行数R和列数C(1 <= R,C <= 100)。下面是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
来源
Don’t know

解题思路

解法一:“人人为我”式递推

L(i,j)表示从点(i,j)出发的最长滑行长度。

一个点(i,j),如果周围没有比它低的点,L(i,j)=1

将所有点按高度从小到大排序。每个点的L值都初始化为1

从小到大遍历所有的点。经过一个点(i,j)时,用递推公式求L(i,j)

  1. 先设每个区域的最长长度为 1;
  2. 对二维数组【此区域】进行从小到大排序
  3. 从找最低点开始逐个遍历,在周围找比它更低的点,更新长度
  4. 最后每个点都更新了他们的最长滑雪长度,找出最大值就可以啦

1.为什么排序?
因为A点的最长滑雪长度是 由 比A点低的B点的最长滑雪长度组成 ,相对低点B的最长滑雪长度是由比点B低的点C的最长滑雪长度组成。
所以从小到大排序后就从最小的点开始更新长度(递推就是一个从已知到未知推导的过程,针对本题,最小值的dp[][]=1已经知道,那从小到大搜索一定可以求出所有值,所以进行了排序操作)

2.为什么用结构体?

2.1因为在排序过程中,排序会改变它在二维数组原来的位置,故可以用结构体保存横纵坐标以及高度,方便接下来计算。

2.2 二维数组不可以用sort()直接排序,所以转化为结构体。

#include<iostream>
#include<algorithm>
using namespace std;
int maxLen[101][101];//存储每个点的最长滑雪长度,动态更新 
int a[101][101];//每个点的高度 
int xy[4][2]={
    
    {
    
    1,0},{
    
    0,1},{
    
    -1,0},{
    
    0,-1}};
struct Node{
    
    
	int x,y,num;//点的横坐标、纵坐标、高度 
}node[10201]; 

bool cmp(struct Node n1,struct Node n2){
    
    
	return n1.num<n2.num;
}
int max(int a,int b){
    
    
	return a>b?a:b;
}
int main(){
    
    
    int r,c,i,j,k=1,x,y,xx,yy,len,maxValue=0;
    cin>>r>>c;
	for(i=1;i<=r;i++){
    
    
		for(j=1;j<=c;j++){
    
    
			cin>>a[i][j];
			node[k].x = i;
			node[k].y = j;
			node[k].num = a[i][j];
			k++;
			maxLen[i][j] = 1;//初始化每个点的长度为1 
		}
	}
	sort(node+1,node+r*c+1,cmp);//从小到大排序 
	for(i=1;i<=r*c;i++){
    
    
		x = node[i].x;
		y = node[i].y;
	    for(j=0;j<4;j++){
    
    //对该点的周围进行遍历比较 
	    	xx = x+xy[j][0];
	    	yy = y+xy[j][1];
	    	if(xx>=1&&xx<=r&&yy>=1&&yy<=c&&a[x][y]>a[xx][yy]){
    
    //xx<=r写成了xx<=c!!! 
	    		maxLen[x][y] = max(maxLen[x][y],maxLen[xx][yy]+1);
	    	}
	    }
	    maxValue = max(maxLen[x][y],maxValue);
	}
     cout<<maxValue<<endl; 
	return 0;
} 

解法二:“我为人人”式递推

L(i,j)表示从点(i,j)出发的最长滑行长度。

一个点(i,j),如果周围没有比它低的点,L(i,j)= 1

将所有点按高度从小到大排序。每个点的L值都初始化为1

从小到大遍历所有的点。经过一个点(i,j)时,要更新他周围的,比它高的点的L值。例如:

if H(i+1,j)> H(i.j) //H代表高度
L(i+1,j) = max(L(i+1,j),L(i,j)+1)

这代码运行结果是对的,但是提交上去却是错的,不知道哪位大佬能看出哪里错!!

#include<iostream>
#include<algorithm>
using namespace std;
int maxLen[101][101];//存储每个点的最长滑雪长度,动态更新 
int a[101][101];//每个点的高度 
int xy[4][2]={
    
    {
    
    1,0},{
    
    0,1},{
    
    -1,0},{
    
    0,-1}};
struct Node{
    
    
	int x,y,num;//点的横坐标、纵坐标、高度 
}node[10201]; 

bool cmp(struct Node n1,struct Node n2){
    
    
	return n1.num<n2.num;
}
int max(int a,int b){
    
    
	return a>b?a:b;
}
int main(){
    
    
    int r,c,i,j,k=1,x,y,xx,yy,len,maxValue=0;
    cin>>r>>c;
	for(i=1;i<=r;i++){
    
    
		for(j=1;j<=c;j++){
    
    
			cin>>a[i][j];
			node[k].x = i;
			node[k].y = j;
			node[k].num = a[i][j];
			k++;
			maxLen[i][j] = 1;//初始化每个点的长度为1 
		}
	}
	sort(node+1,node+r*c+1,cmp);//从小到大排序 
	for(i=1;i<=r*c;i++){
    
    
		x = node[i].x;
		y = node[i].y;
	    for(j=0;j<4;j++){
    
    
	    	xx = x+xy[j][0];
	    	yy = y+xy[j][1];
	    	//在解法一的基础上,下面这段代码做了改动
	    	if(xx>=1&&xx<=r&&yy>=1&&yy<=c&&a[x][y]<a[xx][yy]){
    
    
	    		maxLen[xx][yy] = max(maxLen[x][y]+1,maxLen[xx][yy]);
	    		maxValue = max(maxLen[xx][yy],maxValue);
	    	}
	    }
	    
	}
     cout<<maxValue<<endl; 
	return 0;
} 

解法三:记忆化搜索

写的很详细的博客

猜你喜欢

转载自blog.csdn.net/weixin_45867159/article/details/114142470
今日推荐