鹿我所录的博客

记录我在学习C#中的点点滴滴,记录下以备后来人借鉴。

 

洛谷P1434滑雪-题解

原题:

 

 

 

 

思路:

首先考虑暴搜。

对于每一个点,我记录到这一格为止,走过了多少路。然后枚举四个方向继续递归。直到彻底走不动之后,就停下来更新答案。

但是有个问题——数据规模最大100行100列,如果我以一次递归4个方向来计算,第一层4种,第二层16种,第三层64种,第四层256种,而假设我们从整个地图的中间开始找,至少要花50步找到边界,而此时共有450种方案,这个数是1,267,650,600,228,229,401,496,703,205,376

这个数肯定爆炸

所以我们想到那些我们常用的优化。

第一,剪枝。

对于每一个到达的点,我们开一个数组记忆到这个点的最长步数。

如果最长步数大于这次到达这个点时的步数,我们可以不继续。

第二,记忆化搜索。

仍然记忆最长步数,如果这个点之前走过直接返回这个值。

对于每一个点的记忆值,我们选四个方向的返回值中最大的那个+1

由这个,我们想到了DP。

DP思路与上述记忆化搜索差不多废话记忆化搜索就是DP,详见下附代码

代码:

DP:

#include<bits/stdc++.h>
using namespace std;
int n,m,maxn;
int mp[105][105];
int f[105][105];
struct node
{
    int x;
    int y;
    int w;
}N[10005];
int cnt;
bool cmp(struct node a,struct node b)
{
    return a.w<b.w;
}
int main()
{
    cin >> n >> m;
    for(int i=1;i<=n;i++)
        for(int j=1;j<=m;j++)
        {
            cnt++;
            cin >> mp[i][j];
            N[cnt].x=i;
            N[cnt].y=j;
            N[cnt].w=mp[i][j];
            f[i][j]=1;
        }
    sort(N+1,N+1+cnt,cmp);
    for(int i=1;i<=cnt;i++)
    {
        int x=N[i].x;
        int y=N[i].y;
        int w=N[i].w;
        if(w>mp[x-1][y])
            f[x][y]=max(f[x][y],f[x-1][y]+1);
        if(w>mp[x][y-1])
            f[x][y]=max(f[x][y],f[x][y-1]+1);
        if(w>mp[x+1][y])
            f[x][y]=max(f[x][y],f[x+1][y]+1);
        if(w>mp[x][y+1])
            f[x][y]=max(f[x][y],f[x][y+1]+1);
        if(maxn<f[x][y])
            maxn=f[x][y];
    }
    cout << maxn << endl;
    return 0;
}

  

剪枝(这个写法有一个点超时,吸了氧过的,或许有更好写法):

#include <bits/stdc++.h>
using namespace std;
int n,m;
int sx,sy;
int cnt;
int mp[150][150];
int f[150][150];
bool bk[150][150];
bool vis[150][150];
int tmp;
int ans;
int nxt[4][2]={{0,1},{1,0},{0,-1},{-1,0}};
struct node
{
    int x,y,height;
}N[10050];
bool cmp(struct node a,struct node b)
{
    return a.height>b.height;
}
void dfs(int x,int y,int stp)
{
    bk[x][y]=false;
    cnt++;
    if(f[x][y]>stp)
        return;
    f[x][y]=stp;
    for(int i=0;i<4;i++)
    {
        int tx=x+nxt[i][0];
        int ty=y+nxt[i][1];
        if(tx<=0||tx>n||ty<=0||ty>m)
            continue;
        if(mp[tx][ty]<mp[x][y]&&!vis[tx][ty])
        {
            vis[tx][ty]=true;
            dfs(tx,ty,stp+1);
            vis[tx][ty]=false;
        }
    }
    if(stp>ans)
        ans=stp;
}
int main()
{
    cin >> n >> m;
    for(int i=1;i<=n;i++)
        for(int j=1;j<=m;j++)
            cin >> mp[i][j];
    //下面的循环是重点
    //如果只从最高点开始搜索
    //一旦遇到
    /*0 94 93 92 0
    96 95 98 91 90
    97 98 0 98 89
    98 0 99 0 98*/
    //就会被卡
    //其原因在于
    //从最高点开始搜索,则搜索轨迹是
    /*
    *****
    *****
    **#**
    *###*
    */
    //就这么结束了
    //显然不能覆盖所有点
    //就无法得出正确答案
    for(int i=1;i<=n;i++)
        for(int j=1;j<=m;j++)
            if(!bk[i][j])
            {
                f[i][j]=1;
                dfs(i,j,1);
            }
    cout << ans;
    return 0;
}

  

posted on 2020-08-07 16:03  鹿我所录  阅读(249)  评论(0编辑  收藏  举报

导航