P1434 [SHOI2002]滑雪


原题链接

P1434
题目类型: 普 及 + / 提 高 {\color{yellow}{普及+/提高}} +/
AC记录:

1.Accepted
2.Accepted

题目大意

给你一个 n × m n\times m n×m的矩阵 a a a a i , j a_{i,j} ai,j代表 ( i , j ) (i,j) (i,j)这个地方的高度,你可以从任意一个地方出发,然后走到一个和这个地方四联通并且高度严格小于当前位置高度地方,求你可以走的最长路线长度。

输入格式

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

输出格式

输出区域中你可以走的最长路线长度。
S a m p l e \mathbf{Sample} Sample I n p u t \mathbf{Input} Input

5 5
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

S a m p l e \mathbf{Sample} Sample O u t p u t \mathbf{Output} Output

25

H i n t & E x p l a i n \mathbf{Hint\&Explain} Hint&Explain
直接从 ( 3 , 3 ) (3,3) (3,3)开始然后螺旋走,途径高度为25-24-23-22-21-...-3-2-1

数据范围

对于 100 % 100\% 100%的数据, 1 ≤ n , m ≤ 100 1\le n,m\le 100 1n,m100

解题思路

这题可以用两种方法来做。


记忆化搜索
如果直接使用搜索,按照四联通的方法走的话,绝对会超时。因此我们要使用记搜
在每一次经过一个位置的时候,记录一个 f f f数组,表示当前最长的滑雪路径长度,这样每一个位置最多只用执行一次操作,大大减少了原来的时间复杂度。
核心代码:

int dfs(int x,int y)
{
    if(f[x][y])
        return f[x][y];
    f[x][y]=1;
    for(int i=1; i<=4; i++)
    {
        int xx=x+dx[i],yy=y+dy[i];
        if(xx>0&&xx<=n&&yy>0&&yy<=m&&a[xx][yy]<a[x][y])
            f[x][y]=max(f[x][y],dfs(xx,yy)+1);
    }
    return f[x][y];
}

注意事项

1.在判断方向时,一定要注意不要走错方向!这里给出一个记忆方法:
对于四联通来说,只要 x x x坐标加一减一, y y y坐标也加一减一就可以了

int dx[5]={0,-1,1,0,0};
int dy[5]={0,0,0,-1,1};

对于八连通来说,只要 x x x坐标三个连续的-1和三个连续的0和三个连续的1 y y y坐标连续三个-1,0,1就可以了。这里把(0,0)提前了。

int dx[9]={0,-1,-1,-1,0,0,1,1,1};
int dy[9]={0,-1,0,1,-1,1,-1,0,1};

d p dp dp做法
由于滑雪的路程是从高到低,所以只要你到达了一个点,就不会返回你来的那个点,满足 d p dp dp的无后效性,所以本题可以用 d p dp dp解决。
既然要满足无后效性,那么我们肯定要对整个地图进行排序,记录之前的位置和高度,在按照高度从大到小排序。作者这里用到的是STL里面的priority_queue,如果用了priority_queue,记得要重载()运算符!
排完序后,就可以进行 d p dp dp了。枚举每一个高度,搜索比他小的四联通的高度,由于我们先前已经排好序了,所以会快很多。枚举到一个与他相邻的格子,就要注意进行状态转移了,直接在当前长度上加一即可。
但是最后的答案是 max ⁡ 1 ≤ i ≤ n × m f i \max_{1\le i\le n\times m}f_i max1in×mfi
如果说按照最高的高度可以到达更多个点的话,那么下面这个数据点就过不了:

5 5
2 3 4 5 6
17 1 1 1 7
16 1 25 1 8
15 1 1 1 9
14 13 12 11 10

在这个数据点中, f 25 f_{25} f25的值为2,而标准答案是16
所以说要取 f f f数组里面所有数的最大值。

注意事项:

1.使用priority_queue时要加上头文件#include<queue>,这里的使用方法为priority_queue<obj,vector<obj>,cmp> pq;其中的cmp为单独的一个用来储存()重载的结构体。
2.也是一样,在判断方向的时候一定不要算错!


最后,祝大家早日
AC

上代码

d f s dfs dfs算法

#include<iostream>

using namespace std;

int        n,m;
int        a[1010][1010];
int        f[1010][1010];
int        dx[5]={0,0,0,-1,1};
int        dy[5]={0,-1,1,0,0};

int dfs(int x,int y)
{
    if(f[x][y])
        return f[x][y];
    f[x][y]=1;
    for(int i=1; i<=4; i++)
    {
        int xx=x+dx[i],yy=y+dy[i];
        if(xx>0&&xx<=n&&yy>0&&yy<=m&&a[xx][yy]<a[x][y])
            f[x][y]=max(f[x][y],dfs(xx,yy)+1);
    }
    return f[x][y];
}

int main()
{
    cin>>n>>m;
    for(int i=1; i<=n; i++)
        for(int j=1; j<=m; j++)
            cin>>a[i][j];
    int sum=0;
    for(int i=1; i<=n; i++)
        for(int j=1; j<=m; j++)
            sum=max(sum,dfs(i,j));
    // for(int i=1; i<=n; i++)
    // {
    //     for(int j=1; j<=m; j++)
    //         cout<<f[i][j]<<" ";
    //     cout<<endl;
    // }
    cout<<sum<<endl;
    return 0;
}

d p dp dp算法

#include<iostream>
#include<cstring>
#include<queue>

using namespace std;

struct obj{
    obj(int a=0,int b=0,int c=0):x(a),y(b),val(c){}
    int x,y,val;
};

struct cmp{
    inline bool operator()(obj,obj);
};

inline bool cmp::operator()(obj x,obj y)
{
    return x.val>y.val;
}

priority_queue<obj,vector<obj>,cmp>     pq;
int                                     n,m,tar;
int                                     dx[5]={0,0,0,-1,1};
int                                     dy[5]={0,-1,1,0,0};
int                                     a[110][110];
int                                     f[110][110];

int main()
{
    cin>>n>>m;
    for(int i=1; i<=n; i++)
        for(int j=1; j<=m; j++)
            cin>>a[i][j],pq.push(obj(i,j,a[i][j]));
    memset(f,-0x7f7f7f7f,sizeof(f));
    while(pq.size())
    {
        obj now=pq.top();
        pq.pop();
        int x=now.x,y=now.y,val=now.val;
        f[x][y]=1;
        for(int i=1; i<=4; i++)
        {
            int xx=x+dx[i],yy=y+dy[i];
            if(xx>0&&xx<=n&&yy>0&&yy<=n&&a[xx][yy]<a[x][y])
                f[x][y]=max(f[x][y],f[xx][yy]+1);
        }
        tar=max(tar,f[x][y]);
    }
    cout<<tar<<endl;
    return 0;
}

完美切题 ∼ \sim

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值