zoukankan      html  css  js  c++  java
  • 洛谷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;
    }
    

      

  • 相关阅读:
    预备作业03
    预备作业02
    寒假作业01
    1179 最大的最大公约数(水题)
    HttpWebRequest
    python模拟银行家算法
    Lock锁与Condition监视器(生产者与消费者)。
    synchronized(){}同步代码块笔记(新手笔记,欢迎纠正)
    详解~实现Runnable方法创建线程之为什么要将Runnable接口的子类对象传递给Thread的构造函数
    语义web基础知识学习
  • 原文地址:https://www.cnblogs.com/lujin49/p/13453437.html
Copyright © 2011-2022 走看看