• P1941 飞扬的小鸟


    题意:

    Flappy Bird是一款风靡一时的休闲手机游戏。(笨鸟瞎jb飞︿( ̄︶ ̄)︿)
    游戏界面是一个长为 n,高为 m 的二维平面,
    其中有 k 个管道(忽略管道的宽度)。
    小鸟始终在游戏界面内移动。
    小鸟从游戏界面最左边任意整数高度位置出发,到达游戏界面最右边时,游戏完成。
    小鸟每个单位时间沿横坐标方向右移的距离为 1,竖直移动的距离由玩家控制。
    如果点击屏幕,小鸟就会上升一定高度 X,每个单位时间可以点击多次,效果叠加;
    如果不点击屏幕,小鸟就会下降一定高度 Y。
    小鸟位于横坐标方向不同位置时,上升的高度 X 和下降的高度 Y 可能互不相同。
    小鸟高度等于 0 或者小鸟碰到管道时,游戏失败。
    小鸟高度为 m 时,无法再上升。
    现在,请你判断是否可以完成游戏。如果可以,输出最少点击屏幕数;
    否则,输出小鸟最多可以通过多少个管道缝隙。

    爆搜大法好。。。。。45

    #include<iostream>
    #include<cstring>
    #include<cctype>
    #include<algorithm>
    using namespace std;
    #define int long long
    #define olinr return
    #define _ 0
    #define love_nmr 0
    #define DB double
    struct node
    {
        int up;
        int down;
    };
    node h[10505];
    struct wmy
    {
        int top;
        int low;
        int x;
    };
    wmy limit[10505];
    int n;
    int m;
    bool flag;
    int k;
    int tot;
    int ans=0x7fffffff;
    inline int read()
    {
        int x=0,f=1;
        char ch=getchar();
        while(!isdigit(ch))
        {
            if(ch=='-')
                f=-f;
            ch=getchar();
        }
        while(isdigit(ch))
        {
            x=(x<<1)+(x<<3)+(ch^48);
            ch=getchar();
        }
        return x*f;
    }
    inline void put(int x)
    {
        if(x<0)
        {
            x=-x;
            putchar('-');
        }
        if(x>9)
            put(x/10);
        putchar(x%10+'0');
    }
    inline void dfs(int high,int x,int step,int num)
    {
        if(x==n)
        {
            flag=true;
            ans=min(ans,step);
            return;
        }
        if(x==limit[num].x)
        {
            tot=max(tot,num);
            if(high<=limit[num].low||high>=limit[num].top)  return;
            if(high>h[x].down)
                dfs(high-h[x].down,x+1,step,num+1);
            for(int i=1;;i++)
            {
                if((i-1)*h[x].up+high>m) break;
                dfs(min(m,high+i*h[x].up),x+1,step+i,num+1);
            }
        }
        else
        {
            if(high>h[x].down)
                dfs(high-h[x].down,x+1,step,num);
            for(int i=1;;i++)
            {
                if((i-1)*h[x].up+high>m) break;
                dfs(min(m,high+i*h[x].up),x+1,step+i,num);
            }
        }
    
    }
    signed main()
    {
        n=read();
        m=read();
        k=read();
        for(int i=0;i<n;i++)
        {
            h[i].up=read();
            h[i].down=read();
        }
        limit[1].x=-1;
        for(int i=1;i<=k;i++)
        {
            limit[i].x=read();
            limit[i].low=read();
            limit[i].top=read();
        }
        for(int i=0;i<=m;i++)
            dfs(i,0,0,1);
        if(flag)
        {
            putchar('1');
            putchar('
    ');
            put(ans);
        }
        else
        {
            putchar('0');
            putchar('
    ');
            put(tot);
        }
        olinr ~~(0^_^0)+love_nmr;
    }

    然而,正解居然是背包DP(蒟蒻瑟瑟发抖。。。)

    以f[i][j]代表飞到i,j时用的最少点击次数

    那么如果向上飞,则$f[i][j]=min(f[i][j],f[i-1][j-x[i]*p]+p)$ p为点击次数(枚举)

    然而这样会T

    仔细观察转移方程

    这。。。。。。这TM是完全背包啊QAQ

    不过要用二维转移

    $f[i][j]=min(f[i-1][j-x[i]]+1,f[i][j-x[i]]+1), j epsilon [x[i]+1,m+x[i]] $

    注意要到$x[i]+m$因为跳的时候可能超过m

    不过超过m的部分要给它压回去,相当于在离m很近时跳一次($<x[i]$的距离)到m

    对于自然掉落

    类比一下

    01背包呗(注意:这里是二维,不用倒序枚举)

    对于不合法的边界,再最后重新赋为初始的极大值(千万别忘,因为上面的转移不考虑管道限制)

    #include<cstdio>
    #include<iostream>
    #include<cstring>
    #include<cctype>
    #include<algorithm>
    using namespace std;
    #define olinr return
    #define _ 0
    #define love_nmr 0
    #define DB double
    struct node
    {
        int up;
        int down;
    };
    node h[10505];
    struct wmy
    {
        int top;
        int low;
    };
    wmy limit[10505];
    int n;
    int m;
    bool flag;
    int k;
    int tot;
    int ans;
    int f[10505][2050];
    bool have[10505];
    inline int read()
    {
        int x=0,f=1;
        char ch=getchar();
        while(!isdigit(ch))
        {
            if(ch=='-')
                f=-f;
            ch=getchar();
        }
        while(isdigit(ch))
        {
            x=(x<<1)+(x<<3)+(ch^48);
            ch=getchar();
        }
        return x*f;
    }
    inline void put(int x)
    {
        if(x<0)
        {
            x=-x;
            putchar('-');
        }
        if(x>9)
            put(x/10);
        putchar(x%10+'0');
    }
    int main()
    {
        n=read();
        m=read();
        k=read();
        for(int i=1;i<=n;i++)
        {
            h[i].up=read();
            h[i].down=read();
            limit[i].top=m;
            limit[i].low=1;
        }
        limit[n].top=m;
        limit[n].low=1;
        for(int x,i=1;i<=k;i++)
        {
            x=read();
            limit[x].low=read()+1;
            limit[x].top=read()-1;  
            have[x]=true;      
        }
        memset(f,0x3f,sizeof f);
        for(int i=1;i<=m;i++)
            f[0][i]=0;
        for(int i=1;i<=n;i++)
        {
            for(int j=h[i].up+1;j<=h[i].up+m;j++)  //向上完全背包
                f[i][j]=min(f[i-1][j-h[i].up]+1,f[i][j-h[i].up]+1);
            for(int j=m+1;j<=m+h[i].up;j++)
                f[i][m]=min(f[i][m],f[i][j]);   //超过 m 的部分
            for(int j=1;j<=m-h[i].down;j++)    //向下01背包
                f[i][j]=min(f[i][j],f[i-1][j+h[i].down]);
            for(int j=1;j<limit[i].low;j++)   //不合法的
                f[i][j]=f[0][0];
            for(int j=limit[i].top+1;j<=m;j++)
                f[i][j]=f[0][0];
        }
        ans=f[0][0];
        for(int i=1;i<=m;i++)
            ans=min(ans,f[n][i]);
        if(ans<f[0][0])
        {
            putchar('1');
            putchar('
    ');
            put(ans);
        }
        else
        {
            int pos=0;
            for(int i=n;i>=1;i--,pos=i)
            {
                for(int j=1;j<=m;j++)
                {
                    if(f[i][j]<f[0][0])
                        goto shit; 
                }
            }
            shit:;
            ans=0;
            for(int i=1;i<=pos;i++)
                if(have[i]) ans++;
            put(0);
            putchar('
    ');
            put(ans);
        }
        olinr ~~(0^_^0)+love_nmr;
    }
  • 相关阅读:
    补点基础:Javascript中的类和闭包
    Extjs学习笔记之五——一个小细节renderTo和applyTo的区别
    Extjs学习笔记之八——继承和事件基础
    总结一篇
    再补点基础:Javascript的构造函数和constructor属性
    Extjs学习笔记之六——面版
    Extjs学习笔记之七——布局
    Extjs学习笔记之九——数据模型(上)
    引擎功率与扭矩哪个比较重要
    毕业三年,同学基本都辞职了,大部分人看完很有同感~
  • 原文地址:https://www.cnblogs.com/olinr/p/9552803.html
Copyright © 2020-2023  润新知