问题描述
滑雪区域由一个二维数组给出。数组的每个数字代表点的高度。如下:
一个人可以从某个点滑向上下左右相邻四个点之一,当且仅当高度减小。在上面的例子中,一条可滑行的滑坡为24-17-16-1。当然25-24-23-…-3-2-1更长。事实上,这是最长的一条。
你的任务就是找到最长的一条滑坡,并且将滑坡的长度输出。 滑坡的长度定义为经过点的个数,例如滑坡24-17-16-1的长度是4。
递归+dfs思想:
首先一个点要向上下左右四个方向移动,就可以定义两个一维数组(也可以是一个二维数组)来组成这四个方向:
int dx[4]={1,0,-1,0},dy[4]={0,1,0,-1};
然后一个点往一个方向移动到下一个点(下一个点满足比上一个点高度低),则又遍历到下一个点,相应的滑坡长度也要加一;如果下一个点无论哪个方向都不满足,则退回到上一个点,另选一个方向,相应的滑坡长度也要减一,就可以用递归实现:
if(x>=0 && x<R && y>=0 && y<C && d[x][y]<d[i][j])
{
sum++;
dfs(d,x,y,sum);
sum--;
}
AC代码如下:
#include <iostream>
using namespace std;
int dx[4]={1,0,-1,0},dy[4]={0,1,0,-1};
int c=0;//定义一个总长度
int R,C;//定义行数、列数
void dfs(int d[][105],int i,int j,int sum)
{
if(sum>c)//sum用于递归的时候改变c的值
c=sum;
for(int t=0;t<4;t++)
{
int x=i+dx[t],y=j+dy[t];//x、y是同时改变的 对应四个方向
if(x>=0 && x<R && y>=0 && y<C && d[x][y]<d[i][j])
{
sum++;
dfs(d,x,y,sum);
sum--;//直到上面dfs函数里面for循环完没有一个满足时,sum--并且回到上一个点寻找另一个满足的方向
}
}
}
int main()
{
int d[105][105];
cin>>R>>C;
for(int i=0;i<R;i++)
for(int j=0;j<C;j++)
cin>>d[i][j];
for(int i=0;i<R;i++)
for(int j=0;j<C;j++)
dfs(d,i,j,1);//从d[0][0]这个点一直遍历到d[R-1][C-1]点
cout<<c<<endl;
return 0;
}
这道题用上述方法可能就会存在比如有三个点A、B、C,A点遍历到不满足的B点,然后C点遍历到满足的A点,A点已经知道B点不满足,但是用上述方法,A点有可能又要判断一次B点满不满足,没有记忆功能,加重代码运算量。所以这时我们可以改善代码,用dp+dfs思想。
dp+dfs思想:
新增一个二维数组用于记忆功能并初始化里面数字都为-1:
int dp[105][105];
其他思想差不多,只是在dfs函数里增加一个if判断返回语句,减少代码的运算量:
if(dp[r][c]!=-1)
return dp[r][c];
AC代码如下:
#include<iostream>
#include<algorithm>
using namespace std;
int d[105][105];
int dp[105][105];
int R,C;//定义行数、列数
int dxy[4][2] = {{0,1},{1,0},{0,-1},{-1,0}};//上面用的一维数组,这里定义一个二维数组
int dfs(int r,int c)
{
int x,y;
if(dp[r][c]!=-1) //之前到过这个点处
return dp[r][c];//存放的其实就是这个点能遍历的最长长度
dp[r][c]=1;//从这点开始计算长度
for (int i = 0; i < 4; i++)
{
x = r + dxy[i][0];
y = c + dxy[i][1];
if (x >= 0 && x < R && y >= 0 && y < C && d[r][c] > d[x][y])
dp[r][c]=max(dp[r][c],dfs(x,y)+1);//调用algorithm库里面的max函数,取这个点能遍历的最长长度
}
return dp[r][c];
}
int main()
{
int L=0;
cin >> R >> C;
for (int i = 0; i < R; i++)
for (int j = 0; j < C; j++)
{
cin >> d[i][j];
dp[i][j]=-1;//初始化d[][]数组的同时,将dp数组数值全赋值为-1
}
for (int i = 0; i < R; i++)
for (int j = 0; j < C; j++)
L=max(L,dfs(i,j)); //与上述算法同样遍历,但你会发现从dfs(0,1)开始,for里面的dfs()函数只执行一次了,因为上一个点对应的dp[][]已经不等于-1
cout << L << endl;
return 0;
}
如果还是有点迷惑,你可以在主函数中调用输出dp数组的代码:
for (int i = 0; i < R; i++)
{
for (int j = 0; j < C; j++)
{
cout<<dp[i][j]<<" ";
}
cout<<endl;
}
相信你就会明白的!!!