题目
记忆化搜索
这道题目需要记忆化搜索,如果普通搜索的话,我们有的时候会用到之前所搜索到的结果,这个时候如果我们再去搜索就没有必要了,重复的计算会浪费很多时间, 如果我们记录之前搜索的答案就可以直接使用,节省时间.
举个简单的例子,比如说求斐波那契数时
如果我们用递归来实现,时间很容易就超时了,这就是因为重复计算,比如我们要计算f[6]
f[6]=f[5]+f[4] , 如果我们在之前有记录, 就可以直接使用了 ,就像我们通过循环来实现斐波那契数,
如果我们没有记录 就不得不要再求一遍f[5]和f[4] ,如果有记录就直接拿来用了
下面直接看代码(附带注释)
#include<bits/stdc++.h>
using namespace std;
#define ll long long
const int N = 1e2+9;
int r,c,a[N][N],d[N][N];
int dx[4]={1,-1,0,0}; //四个方向
int dy[4]={0,0,1,-1};
int dfs(int x , int y){
if(d[x][y]) return d[x][y]; //如果有记忆就直接用了
d[x][y]=1; //起点也计算长度
for(int i=0 ; i<4 ;i++){
int xx=x+dx[i],yy=y+dy[i]; // 四个方向
if(xx>0&&yy>0&&xx<=r&&yy<=c&&a[x][y]>a[xx][yy]){
//保证xx,yy合法并且从高划到低才搜索
dfs(xx,yy);
d[x][y]=max(d[x][y],d[xx][yy]+1);
}
}
return d[x][y];
}
int main(){
ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
cin >>r >> c;
for(int i= 1 ;i <= r ;i++ )
for(int j = 1; j<=c ; j ++)
cin >> a[i][j];
int ans =0 ;
for(int i =1 ;i <= r ; i++)
for(int j =1 ;j<=c ; j++)
//dfs返回以(i,j)为起点出发的最长距离
ans=max(ans,dfs(i,j)); //取最大值
cout << ans ;
}
优先队列
这道题也可以用dp来做 , 但是dp 我们需要考虑无后效性,如果我们简单的一个个遍历 , 肯定是没有无后效性的
因为这个题目只能从低向下滑,那如果我们从从低到高的话,就可以了,先算低的点对后面算高的点没有影响 这就是我们为什么要用优先队列了
下面直接看代码(附带注释)
#include<bits/stdc++.h>
using namespace std;
#define ll long long
const int N = 1e2+9;
int r,c,a[N][N],d[N][N];
int dx[4]={1,-1,0,0}; //四个方向
int dy[4]={0,0,1,-1};
struct node {
int i,j,num; //存储点的坐标和高度
};
struct cmp {
bool operator()(node x , node y){
return x.num>y.num;
}
};//优先队列小的在前面
int main(){
ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
priority_queue<node,vector<node>,cmp>pq;
cin >> r >> c;
for(int i=1 ; i<=r ; i++ )
for (int j=1 ;j <=c ; j++)
{
d[i][j]=1; //因为起点算1,所以每个坐标初始长读为1
node b;
cin >> a[i][j];
b.i=i;b.j=j;b.num=a[i][j];
pq.push(b); //将一个点存进去
}
int ans =0 ;
while (!pq.empty()){
node g = pq.top();
pq.pop();
for(int i=0;i<4;i++){
int xx=g.i+dx[i],yy=g.j+dy[i];//四个方向
if(xx>0&&xx<=r&&yy>0&&yy<=c&&a[g.i][g.j]>a[xx][yy]) //在合法的时候,就比较大小
d[g.i][g.j]=max(d[g.i][g.j],d[xx][yy]+1);//dp
}
ans = max(ans,d[g.i][g.j]); // 取最大值
}
cout << ans;
}