洛谷 P1434 [SHOI2002]滑雪

洛谷 P1434 [SHOI2002]滑雪

题目传送门

题目描述

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

一个人可以从某个点滑向上下左右相邻四个点之一,当且仅当高度会减小。在上面的例子中,一条可行的滑坡为 2424-1717-1616-11(从 2424 开始,在 11 结束)。当然 2525-2424-2323-ldots…-33-22-11 更长。事实上,这是最长的一条。

输入格式

输入的第一行为表示区域的二维数组的行数 RR 和列数 CC。下面是 RR 行,每行有 CC 个数,代表高度(两个数字之间用 11 个空格间隔)。

输出格式

输出区域中最长滑坡的长度。

输入输出样例

输入 #1复制

输出 #1复制

说明/提示

对于 100%100% 的数据,1leq R,Cleq 1001≤R,C≤100。

题解:

作为一道记忆化搜索的题,我硬是拿DP做的。

作为本蒟蒻恢复训练后的第一道题

一开始想的很简单,非常容易得知状态是(dp[i][j])表示到达((i,j))点的最长滑雪路径,最后从头到尾统计一遍最大的(dp[i][j])就是答案了。

然后开始转移,就是如果((i,j))周围的四个点比这个点高(因为只有高的能往低处滑),就更新(dp[i][j])取最大就可以。

然后挂。

百思不得其解(果然半年停训停傻了)我觉得思路比较完美,因为是一道黄题,觉得思维强度也就应该是这水平(逃)

后来发现,我直接扫描的转移不是最优的。就是因为转移的时候还没有计算的那部分有可能更优,然而还没来得及被计算。

就像这样:(显示的是DP数组)

2 5 3 6 9 8
2 6 6 1 1 1
1 1 1 1 1 1
1 1 1 1 1 1
1 1 1 1 1 1

当前转移到第二行第四列,但是只能从上、左两个状态转移得到,事实上右、下的状态有可能更优。所以导致答案统计不全。

那么怎么办呢?

这就涉及到了DP顺序的问题。以我看来,DP顺序需要满足两种条件:第一种,转移最优,第二种,无后效性。

我们分析问题容易得出,如果先统计低的,后统计高的,那么就不会有转移上的问题。在当前点,只有比它低的能转移到它。

所以把矩阵所有的值进行排序,然后用结构体构建映射。最后按照这个顺序来转移就可以。整个过程可以用优先队列实现。

代码:

#include<cstdio>
#include<queue>
#include<algorithm>
#include<vector>
using namespace std;
const int maxn=110;
int n,m,ans;
int map[maxn][maxn];
int dp[maxn][maxn];//dp[i][j]表示(i,j)点的最长路
struct node
{
    int x,y,val;
}a[10010];
int tot;
struct cmp
{ 
    bool operator()(node x,node y)
    {
        return x.val<y.val;
    }
};
priority_queue <node,vector<node>,cmp> q;
void judge(int x,int y)
{
    if(map[x-1][y]>map[x][y])
        dp[x][y]=max(dp[x][y],dp[x-1][y]+1);
    if(map[x+1][y]>map[x][y])
        dp[x][y]=max(dp[x][y],dp[x+1][y]+1);
    if(map[x][y-1]>map[x][y])
        dp[x][y]=max(dp[x][y],dp[x][y-1]+1);
    if(map[x][y+1]>map[x][y])
        dp[x][y]=max(dp[x][y],dp[x][y+1]+1);
}
int main()
{
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++)
        for(int j=1;j<=m;j++)
        {
            scanf("%d",&map[i][j]);
            dp[i][j]=1;
            a[++tot].val=map[i][j];
            a[tot].x=i;
            a[tot].y=j;
            q.push(a[tot]);
        }
    while(!q.empty())
    {
        node now=q.top();
        int xx=now.x;
        int yy=now.y;
        judge(xx,yy);
        q.pop();
    }
    for(int i=1;i<=n;i++)
        for(int j=1;j<=m;j++)
            ans=max(ans,dp[i][j]);
    printf("%d",ans);
    return 0;
}
原文地址:https://www.cnblogs.com/fusiwei/p/13220790.html