P1434 [SHOI2002] 滑雪 (记忆化搜索 , 优先队列)

题目

记忆化搜索

这道题目需要记忆化搜索,如果普通搜索的话,我们有的时候会用到之前所搜索到的结果,这个时候如果我们再去搜索就没有必要了,重复的计算会浪费很多时间, 如果我们记录之前搜索的答案就可以直接使用,节省时间.

举个简单的例子,比如说求斐波那契数时

如果我们用递归来实现,时间很容易就超时了,这就是因为重复计算,比如我们要计算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;      
}

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值