[luoguP1941] 飞扬的小鸟(DP)

传送门

动归,用f[i][j]表示到达第I列高度为j时最少需要飞的次数,容易想到最裸的转移:

f[i][j]=min(min(f[i-1][j-up[i-1]*k]+k),f[i-1][j+down[i-1]])

但是会超时

考虑怎么优化k的循环,发现k可以从k-1转移过来,从图上来理解就是比如k=2时,相当于可以先从i-1列飞一次飞到i列的j-up[i-1]位置,然后再往上跳一次跳到i的j位置,也就是f[i][j]可以从f[i]

[j-up[i-1]]+1转移来,这里需要注意几个地方

1.由于f[i][j-up[i-1]]相当于是中转的位置,所以无论那个位置是不是管道都要做

2.要保证f[i][j-up[i-1]]可以充当中转,所以必须先做一次只飞不掉的,再做一次掉下来的,否则会出现f[i][j-up[i-1]]位置可能是从i-1列掉下来得到的,此时不能充当中转

3.要特殊处理高度为m的情况(看题目)

——代码

 1 #include <cstdio>
 2 #include <iostream>
 3
 4 const int INF = 19260817, N = 10001, M = 1001;
 5 int n, m, k, b, ans = INF, sum;
 6 int x[N], y[N], l[N], h[N], f[2][M];
 7
 8 inline int read()
 9 {
10     int x = 0, f = 1;
11     char ch = getchar();
12     for(; !isdigit(ch); ch = getchar()) if(ch == ‘-‘) f = -1;
13     for(; isdigit(ch); ch = getchar()) x = (x << 1) + (x << 3) + ch - ‘0‘;
14     return x * f;
15 }
16
17 inline int min(int x, int y)
18 {
19     return x < y ? x : y;
20 }
21
22 int main()
23 {
24     int i, j, p;
25     n = read();
26     m = read();
27     k = read();
28     for(i = 0; i < n; i++)
29     {
30         x[i] = read();
31         y[i] = read();
32     }
33     for(i = 1; i <= k; i++)
34     {
35         p = read();
36         l[p] = read();
37         h[p] = read();
38     }
39     for(i = 1; i <= n; i++)
40     {
41         for(j = 1; j <= m; j++) f[i & 1][j] = INF;
42         for(j = x[i - 1] + 1; j <= m; j++)
43             f[i & 1][j] = min(f[i & 1][j], f[i & 1 ^ 1][j - x[i - 1]] + 1),
44             f[i & 1][j] = min(f[i & 1][j], f[i & 1][j - x[i - 1]] + 1);
45         for(j = m - x[i - 1]; j <= m; j++)
46             f[i & 1][m] = min(f[i & 1][m], f[i & 1 ^ 1][j] + 1),
47             f[i & 1][m] = min(f[i & 1][m], f[i & 1][j] + 1);
48         for(j = 1; j <= m - y[i - 1]; j++) f[i & 1][j] = min(f[i & 1][j], f[i & 1 ^ 1][j + y[i - 1]]);
49         if(l[i]) for(j = 1; j <= l[i]; j++) f[i & 1][j] = INF;
50         if(h[i]) for(j = h[i]; j <= m; j++) f[i & 1][j] = INF;
51         if(l[i] || h[i])
52         {
53             b = 0;
54             for(j = l[i] + 1; j < h[i]; j++)
55                 if(f[i & 1][j] < INF)
56                 {
57                     b = 1;
58                     break;
59                 }
60             if(b) sum++;
61             else break;
62         }
63     }
64     if(i == n + 1)
65     {
66         for(j = 1; j <= m; j++) ans = min(ans, f[n & 1][j]);
67         printf("1\n%d\n", ans);
68     }
69     else printf("0\n%d\n", sum);
70     return 0;
71 }

时间: 2024-07-30 10:20:22

[luoguP1941] 飞扬的小鸟(DP)的相关文章

P1941 飞扬的小鸟[dp]

题目描述 Flappy Bird是一款风靡一时的休闲手机游戏.玩家需要不断控制点击手机屏幕的频率来调节小鸟的飞行高度,让小鸟顺利通过画面右方的管道缝隙.如果小鸟一不小心撞到了水管或者掉在地上的话,便宣告失败. 为了简化问题,我们对游戏规则进行了简化和改编: 游戏界面是一个长为 nn,高为 mm 的二维平面,其中有 kk 个管道(忽略管道的宽度). 小鸟始终在游戏界面内移动.小鸟从游戏界面最左边任意整数高度位置出发,到达游戏界面最右边时,游戏完成. 小鸟每个单位时间沿横坐标方向右移的距离为 11,

cogs1805 飞扬的小鸟 dp

填坑$ing$--链接:http://cogs.pro/cogs/problem/problem.php?pid=1805 题意:一堆管子,问怎么用最少点击次数穿出去. 就是个裸背包啊--优化都没有-- 另外这份代码在$UOJ$上被$Hack$了,有没有某位$dalao$帮忙找找问题-- 1 #include<iostream> 2 #include<cstdio> 3 #include<algorithm> 4 #include<cstring> 5 us

NOIP2014飞扬的小鸟[DP][WRONG]

坑人啊朴素的dp 75分 用了完全背包才是80分,结果普遍偏小 为什么啊啊啊啊啊 等以后再写一遍吧 //80 #include<iostream> #include<cstdio> #include<cstring> using namespace std; const int N=10005,M=1005,INF=1e9; int n,m,k, x,y,p,ll,hh; int up[N],down[N],l[N],h[N], has[N]; int f[N][M];

luogu P1941 飞扬的小鸟

二次联通门 : luogu P1941 飞扬的小鸟 /* luogu P1941 飞扬的小鸟 dp 向上飞是完全背包,向下掉就是01背包 分情况讨论一下 最后合并一下 */ #include <cstdio> #include <iostream> #include <cstring> const int BUF = 123123123; char Buf[BUF], *buf = Buf; inline void read (int &now) { for (

[ NOIP ][ NOIP_2014D1T3 ][ 动态规划 ] 飞扬的小鸟

飞扬的小鸟(Flappy Bird) 描述 Flappy Bird 是一款风靡一时的休闲手机游戏.玩家需要不断控制点击手机屏幕的频率来调节小鸟的飞行高度,让小鸟顺利通过画面右方的管道缝隙.如果小鸟一不小心撞到了水管或者掉在地上的话,便宣告失败. 为了简化问题,我们对游戏规则进行了简化和改编: 游戏界面是一个长为 n,高为 m 的二维平面,其中有k 个管道(忽略管道的宽度). 小鸟始终在游戏界面内移动.小鸟从游戏界面最左边 任意整数高度位置出发,到达游戏界面最右边时,游戏完成. 小鸟每个单位时间沿

codevs 3729 飞扬的小鸟 x

3729 飞扬的小鸟 时间限制: 1 s 空间限制: 128000 KB 题目等级 : 黄金 Gold 题目描述 Description 输入描述 Input Description 输出描述 Output Description 输出文件名为 bird.out. 共两行. 第一行,包含一个整数,如果可以成功完成游戏,则输出 1,否则输出 0. 第二行,包含一个整数,如果第一行为 1,则输出成功完成游戏需要最少点击屏幕数, 否则,输出小鸟最多可以通过多少个管道缝隙. 样例输入 Sample In

洛谷 【P1941】飞扬的小鸟

P1941 飞扬的小鸟 题目描述 Flappy Bird 是一款风靡一时的休闲手机游戏.玩家需要不断控制点击手机屏幕的频率来调节小鸟的飞行高度,让小鸟顺利通过画面右方的管道缝隙.如果小鸟一不小心撞到了水管或者掉在地上的话,便宣告失败. 为了简化问题,我们对游戏规则进行了简化和改编: 游戏界面是一个长为n ,高为 m 的二维平面,其中有k 个管道(忽略管道的宽度). 小鸟始终在游戏界面内移动.小鸟从游戏界面最左边任意整数高度位置出发,到达游戏界面最右边时,游戏完成. 小鸟每个单位时间沿横坐标方向右

洛谷P1941 飞扬的小鸟 动态规划

洛谷P1941 飞扬的小鸟 动态规划 这道题主要要注意一下飞到m以上之后高度还是 m 这个就要在判断一下 比较直接暴力的动归 是 O(N^3) f[ i ][ j ] 到 i ,j 这个位置 所需要的最少点击次数 如果不能到,就是无限大 f[ i ][ j ] = min(f[ i-1 ][ j-up[i-1] ] +1 , f[ i-1 ][ j+down[i-1] ] ) 因为可以向上飞无限次 这其实就相当于是无限背包 然后 f[ i ][ j ] 就可以从 f[ i ][ j-up[ i-

noip2014飞扬的小鸟

飞扬的小鸟 题目链接 题意: 一个二维平面,长为\(n\),宽为\(m\),其中有\(k\)个管道,小鸟从最左边任意整数高度位置出发,到达游戏界面最右边时,游戏完成. 小鸟每个单位时间沿着\(x\)轴向右移动一个单位距离,小鸟在从\(i\)移动到\(i +1\)时,玩家可以选择是否点击屏幕(可以点击多次),若不点击,小鸟将下降\(y_i\)单位距离,若点击\(j\)次,小鸟的上升距离为\(j\times x_i\). 当小鸟碰到管壁或纵坐标等于\(0\)时,游戏结束.小鸟的高度可以不停上升,但最