• 【动态规划】luoguP1941 飞扬的小鸟


    细节总是打挂选手:)

    题目描述

    Flappy Bird是一款风靡一时的休闲手机游戏。玩家需要不断控制点击手机屏幕的频率来调节小鸟的飞行高度,让小鸟顺利通过画面右方的管道缝隙。如果小鸟一不小心撞到了水管或者掉在地上的话,便宣告失败。

    为了简化问题,我们对游戏规则进行了简化和改编:

    游戏界面是一个长为 nn ,高为 mm 的二维平面,其中有 kk 个管道(忽略管道的宽度)。

    小鸟始终在游戏界面内移动。小鸟从游戏界面最左边任意整数高度位置出发,到达游戏界面最右边时,游戏完成。

    小鸟每个单位时间沿横坐标方向右移的距离为 11 ,竖直移动的距离由玩家控制。如果点击屏幕,小鸟就会上升一定高度 XX ,每个单位时间可以点击多次,效果叠加;如果不点击屏幕,小鸟就会下降一定高度 YY 。小鸟位于横坐标方向不同位置时,上升的高度 XX 和下降的高度 YY 可能互不相同。

    小鸟高度等于 00 或者小鸟碰到管道时,游戏失败。小鸟高度为 mm 时,无法再上升。

    现在,请你判断是否可以完成游戏。如果可以,输出最少点击屏幕数;否则,输出小鸟最多可以通过多少个管道缝隙。

    输入输出格式

    输入格式:

    第 11 行有 33 个整数 n, m, kn,m,k ,分别表示游戏界面的长度,高度和水管的数量,每两个整数之间用一个空格隔开;

    接下来的 nn 行,每行 22 个用一个空格隔开的整数 XX 和 YY ,依次表示在横坐标位置 0 sim n-10∼n−1 上玩家点击屏幕后,小鸟在下一位置上升的高度 XX ,以及在这个位置上玩家不点击屏幕时,小鸟在下一位置下降的高度 YY 。

    接下来 kk 行,每行 33 个整数 P, L, HP,L,H ,每两个整数之间用一个空格隔开。每行表示一个管道,其中 PP 表示管道的横坐标, LL 表示此管道缝隙的下边沿高度, HH 表示管道缝隙上边沿的高度(输入数据保证 PP 各不相同,但不保证按照大小顺序给出)。

    输出格式:

    共两行。

    第一行,包含一个整数,如果可以成功完成游戏,则输出 11 ,否则输出 00 。

    第二行,包含一个整数,如果第一行为 11 ,则输出成功完成游戏需要最少点击屏幕数,否则,输出小鸟最多可以通过多少个管道缝隙。


    题目分析

    dp方程当然是很简单的,就是个普普通通的计数dp。

    但是细节……呃,反正第一次提交(赶着吃午饭)的话只有60pts……改了一下zz错误是75pts……

    哎……可能在NOIP考场上最多只能得75pts啊,还是人太菜了。

    主要的一些点就是:

    1. 飞到上边界不会死
    2. 同一秒可以多次跳跃
    3. dp时间复杂度的小优化

    前两个都是明眼人都能看出来的,第三个的话还是要一定dp的功底吧。

    具体来说就是因为同一秒能够跳很多次,那么如果每一次跳都拿来转移的话,显然(然而之前我并没有仔细分析……)这个复杂度可以被卡上天。

    那么实际上跳多次可以看成是这个东西。也就是从同一横坐标的地方直接跳上来。

    具体实现好像细节很多?但也不算很多……可能还是本身太菜了,总是打挂。

    这里有一篇很好的讲解:https://www.luogu.org/blog/xxzh2425/fei-yang-di-xiao-niao-ti-xie-p1941-post

     1 #include<bits/stdc++.h>
     2 const int maxn = 10035;
     3 const int maxm = 1003;
     4 
     5 int x[maxn],y[maxn],l[maxn],r[maxn];
     6 int f[maxn][maxm];
     7 bool vis[maxn];
     8 int n,m,k,mx;
     9 
    10 int read()
    11 {
    12     char ch = getchar();
    13     int num = 0;
    14     bool fl = 0;
    15     for (; !isdigit(ch); ch = getchar())
    16         if (ch=='-') fl = 1;
    17     for (; isdigit(ch); ch = getchar())
    18         num = (num<<1)+(num<<3)+ch-48;
    19     if (fl) num = -num;
    20     return num;
    21 }
    22 bool dp()
    23 {
    24     int tot = 0;
    25     for (int i=1; i<=n; i++)
    26     {
    27         bool fl = 0;
    28         for (int j=x[i-1]; j<=m; j++)
    29         {
    30             if (j==m)
    31                 for (int h=m-x[i-1]; h<=m; h++)
    32                     f[i][m] = std::min(f[i][m], f[i-1][h]+1),
    33                     f[i][m] = std::min(f[i][m], f[i][h]+1);
    34             // if (j-x[i-1]<=r[i-1]&&j-x[i-1]>=l[i-1])
    35                 f[i][j] = std::min(f[i][j], f[i-1][j-x[i-1]]+1);
    36             // if (j-x[i-1]>=l[i]&&j-x[i-1]<=r[i])
    37                 f[i][j] = std::min(f[i][j], f[i][j-x[i-1]]+1);
    38         }
    39         for (int j=l[i]; j<=r[i]; j++)
    40         {
    41             if (j+y[i-1]>=l[i-1]&&j+y[i-1]<=r[i-1])
    42                 f[i][j] = std::min(f[i][j], f[i-1][j+y[i-1]]);
    43             if (f[i][j]!=f[0][0]) fl = 1;
    44         }
    45         for (int j=l[i]-1; j>=1; j--)
    46             f[i][j] = f[0][0];
    47         for (int j=r[i]+1; j<=m; j++)
    48             f[i][j] = f[0][0];
    49         if (!fl){
    50             mx = tot;
    51             return 0;
    52         }
    53         if (vis[i]) tot++;
    54     }
    55     return 1;
    56 }
    57 int main()
    58 {
    59     // freopen("testdata.in","r",stdin);
    60     memset(f, 0x3f3f3f3f, sizeof f);
    61     n = read(), m = read(), k = read();
    62     for (int i=0; i<n; i++)
    63     {
    64         x[i] = read(), y[i] = read();
    65         l[i] = 1, r[i] = m;
    66     }
    67     l[n] = 1, r[n] = m;
    68     for (int i=1; i<=m; i++) f[0][i] = 0;
    69     for (int i=1; i<=k; i++)
    70     {
    71         int a = read(), b = read(), c = read();
    72         vis[a] = 1, l[a] = b+1, r[a] = c-1;
    73     }
    74     if (dp()){
    75         int ans = f[0][0];
    76         for (int i=1; i<=m; i++)
    77             ans = std::min(ans, f[n][i]);
    78         printf("1
    %d
    ",ans);
    79     }else printf("0
    %d
    ",mx);
    80     return 0;
    81 }

    END

  • 相关阅读:
    3.1 history跳转页面产生跨域问题
    2021年6月7日 团队冲刺第二阶段04
    2021年6月6日 团队冲刺第二阶段03
    2021年6月5日 团队冲刺第二阶段02
    2021年6月4日 团队冲刺第二阶段01
    2021年6月3日
    2021年6月2日
    2021年6月1日
    2021年5月31日
    2021年5月30日
  • 原文地址:https://www.cnblogs.com/antiquality/p/9286121.html
Copyright © 2020-2023  润新知