洛谷 P1434 [SHOI2002] 滑雪

P1434 [SHOI2002] 滑雪 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)

这道题数据很水,可以用记忆化过,这里说一下堆优化+DP的方法

 

首先是常用的DP逆向思维,也是此题最终的思路:倒着来

很多情况下,正这来,是让DP[i]推向多个状态,而倒这来,是多个状态推向DP[i].

题目说是从从高到低:对于(i,j) 到它的四个方向的块,应该是DP[i][j]到了DP[ i+dx[] ] [ j+dy[] ],但显然这不好,我们从一个状态转为四个状态,这很不方便

 

 

但是我们如果逆向思维,从低到高走,题意是等价的,这是就从DP[ i+dx[] ] [ j+dy[] ]到 DP[i][j],四个状态转为一个状态,就舒服多了

 

 我们令DP[i][j]为走到这个(i,j)的最多步骤

显然DP[i][j]初始值为 1 ,这步没了就WA50分

因为这个是有方向的,我们就不能傻傻的for枚举DP,这也一定不是最优值

从贪心的角度考虑,既然是从低到高走,那么每次我们从当前的最低(i,j)开始,来算出DP[i][j]的值,DP[i][j]就是从它的四个方向转移过来,这时就体现了倒这来的好处

如何每次稳定的拿到最低呢?这是就用堆来维护就可以了。自定义堆,存入下标,高度,让高度进行排序,使得堆顶是最小的高度。

#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define mp make_pair
#define pb push_back   //vector函数
#define popb pop_back  //vector函数
#define fi first
#define se second
const int N=200;
//const int M=;
//const int inf=0x3f3f3f3f;     //一般为int赋最大值,不用于memset中
//const ll INF=0x3ffffffffffff; //一般为ll赋最大值,不用于memset中
int T,n,m,h[N][N],dp[N][N];
int dx[5]={0,0,1,-1};
int dy[5]={1,-1,0,0};
struct node
{
    int x,y,h;
    friend bool operator <(const node &a,const node &b) { return a.h>b.h; } 
};
priority_queue<node> q;
inline int read()
{
    int x=0,f=1;char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}
    return x*f;
}
int main()
{
//    freopen("","r",stdin);
//    freopen("","w",stdout);
    n=read(),m=read();
    for(int i=1;i<=n;i++)
    {
        for(int j=1;j<=m;j++)
        {
            dp[i][j]=1; //这个很重要,没这个就WA了 
            h[i][j]=read();
            q.push(node{i,j,h[i][j]});
        }
    }
    int ans=0;
    while(!q.empty())
    {
        node x=q.top();
        q.pop();
        for(int i=0;i<4;i++)
        {
            int tx=dx[i]+x.x,ty=dy[i]+x.y;
            if(h[tx][ty]<h[x.x][x.y]) dp[x.x][x.y]=max(dp[x.x][x.y],dp[tx][ty]+1);
        }
        ans=max(ans,dp[x.x][x.y]);
    }
    printf("%d\n",ans);
    return 0;
}

 

posted @ 2023-01-23 22:01  QAQ啥也不会  阅读(89)  评论(0)    收藏  举报