滑雪
题目链接:滑雪
题目描述
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(从24开始,在1结束)。当然25-24-23-…-3-2-1更长。事实上,这是最长的一条。
输入格式
输入的第一行为表示区域的二维数组的行数R和列数C(1≤R,C≤100)。下面是R行,每行有C个数,代表高度(两个数字之间用1个空格间隔)。
输出格式
输出区域中最长滑坡的长度。
输入输出样例
输入
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
解题思路①
这道题可以用记忆化搜索的方法来做将每一个节点的值都求一遍,用数组标记,最后取出最大值,输出答案
程序如下:
#include<cstdio>
#include<iostream>
using namespace std;
int n,m,a[110][110],f[110][110],maxn;
const int fx[5]={0,-1,1,0,0};
const int fy[5]={0,0,0,1,-1};
int dfs(int x,int y)//搜索
{
if(f[x][y])//记忆化
return f[x][y];
for(int i=1;i<=4;i++)
if(a[x+fx[i]][y+fy[i]]<a[x][y]&&x+fx[i]<=n&&x+fx[i]>0&&y+fy[i]>0&&y+fy[i]<=m)//判断是否合法
f[x][y]=max(dfs(x+fx[i],y+fy[i])+1,f[x][y]);
return f[x][y];
}
int main()
{
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
scanf("%d",&a[i][j]);
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
{
f[i][j]=dfs(i,j);
if(f[i][j]>maxn)//取最大值
maxn=f[i][j];
}
cout<<maxn+1<<endl;//因为本身也算一个节点
}
解题思路②
同样的,这道题也是一个动态规划,从高度较低的点向高度较高的点推,再找到最大的点,输出它的值。但是动态规划必须是有序的,所以在这里作者将这个二维的数组展开成一维的,进行排序后它就有序了。
程序如下:
#include<iostream>
#include<algorithm>
#include<cstdio>
using namespace std;
int n,m,t[10010],maxn;
const int fx[5]={0,-1,1,0,0};
const int fy[5]={0,0,0,1,-1};
struct xy{
int b;//值
int x;//横坐标
int y;//纵坐标
}f[10010];
bool bi(xy q,xy p)
{
return q.b<p.b;
}
int main()
{
cin>>n>>m;
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
{
scanf("%d",&f[(i-1)*m+j].b);
f[(i-1)*m+j].x=i;f[(i-1)*m+j].y=j;//预处理
}
sort(f+1,f+n*m+1,bi);//排序
for(int i=1;i<=n*m;i++)//枚举全部
for(int j=i-1;j>0;j--)//从高到低
for(int k=1;k<=4;k++)//四个方向
if(f[i].x==f[j].x+fx[k]&&f[i].y==f[j].y+fy[k]&&f[i].b>f[j].b)//判断是否合法
{
t[i]=max(t[j]+1,t[i]);//动态转移
if(t[i]>maxn)//取最大值
maxn=t[i];
}
cout<<maxn+1;//因为本身也算一个节点
}
这里其实有一个需要注意的点:同一高度是滑不过去的。
分享
作者刷红的一片天