Luogu 1941 【NOIP2014】飞扬的小鸟 (动态规划)

Description

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

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

  • 游戏界面是一个长为n ,高为 m 的二维平面,其中有k 个管道(忽略管道的宽度)。
  • 小鸟始终在游戏界面内移动。小鸟从游戏界面最左边任意整数高度位置出发,到达游戏界面最右边时,游戏完成。
  • 小鸟每个单位时间沿横坐标方向右移的距离为1,竖直移动的距离由玩家控制。如果点击屏幕,小鸟就会上升一定高度X ,每个单位时间可以点击多次,效果叠加;
  • 如果不点击屏幕,小鸟就会下降一定高度Y 。小鸟位于横坐标方向不同位置时,上升的高度X 和下降的高度Y 可能互不相同。
  • 小鸟高度等于0 或者小鸟碰到管道时,游戏失败。小鸟高度为 m 时,无法再上升。

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

Input

第1 行有3 个整数n ,m ,k,分别表示游戏界面的长度,高度和水管的数量,每两个整数之间用一个空格隔开;接下来的n 行,每行2 个用一个空格隔开的整数X 和Y ,依次表示在横坐标位置0 ~n- 1上玩家点击屏幕后,小鸟在下一位置上升的高度X ,以及在这个位置上玩家不点击屏幕时,小鸟在下一位置下降的高度Y 。接下来k 行,每行3 个整数P ,L ,H ,每两个整数之间用一个空格隔开。每行表示一个管道,其中P 表示管道的横坐标,L 表示此管道缝隙的下边沿高度为L ,H 表示管道缝隙上边沿的高度(输入数据保证P 各不相同,但不保证按照大小顺序给出)。

Output

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

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

Sample Input

10 10 6

3 9

9 9

1 2

1 3

1 2

1 1

2 1

2 1

1 6

2 2

1 2 7

5 1 5

6 3 5

7 5 8

8 7 9

9 1 3

Sample Output

1

6

Http

Luogu:https://www.luogu.org/problem/show?pid=1941

Source

动态规划

解决思路

这道题目讲起来并不算太难,即完全背包+01背包。但细节不好调。

设F[i][j]表示在第i列高度为j的时候的最小点击数,令X[i]表示在第i列点击一次向上飞的距离,令Y[i]表示在第i列不点击是下降的距离。首先动态转移方程,因为鸟向上飞是可以点击多次的,为了防止出现在同一列即向上又向下的情况,所以先做完全背包。

\(F[i][j]=min(F[i-1][j-X[i-1],F[i][j-X[i-1])\{j \in [X[i-1]+1,m]\}\)

然后再做01背包

\(F[i][j]=min(F[i][j],F[i-1][j+Y[i-1])\{j \in [1,m-Y[i-1]] \}\)

另外还有特判高度为m的情况,也就是对于\(j\in [m-Y[i-1],m]\)有

\(F[i][m]=min(F[i][m],F[i][j]+1,F[i-1][j]+1)\)

大致的思路就是这样,下面讲一讲本题一些细节。

  • 鸟是不能飞到高度为0的地方的,所以转移也不能从0转移过来,所以在考虑向上飞的情况时,j应该从X[i-1]+1开始,注意一定要+1
  • 注意管道,如果题目中给出的下管道高度是L,上管道高度是R,则实际可以经过的范围应该是[L+1,R-1],也就是说,如果有管道,不管上面的管道长度是多少,高度为m的地方都是不能走的
  • 做向上飞的情况的时候要注意,虽然说理论上讲实际能飞的距离是[L+1,R-1],但我们依然要从X[i-1]+1开始循环到最大,就算X[i-1]+1这个高度实际上是管道。为什么呢?这是由完全背包的性质决定的。比如说当前第i列下管道的高度是10,上一次点一次能飞的高度是3,那么如果我们从10+1=11开始循环,就只能从F[i-1][11-3]转移过来,而实际上可能F[i-1][2]点3次后的解更优。(自己手动模拟一下完全背包的运作过程,然后你就能发现这个问题)。最后执行完后我们再把是管道的地方的F置为不可解。
  • 如果某一次的所有F都为不可解,那么说明无解,此时输出鸟飞过的管道个数

(更多细节请参考代码,已经在代码中标记出来啦)

代码

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<algorithm>
using namespace std; const int maxN=20011;
const int maxM=2011;
const int inf=147483647;//注意这里inf去掉了前面的2,这里是为了方便做加法时不会出现负数 int n,m,K;
int X[maxN];//X[i]表示第i列点一次能飞的高度
int Y[maxN];//Y[i]表示第i列如果不点降低的高度
bool is_pipe[maxN];//is_pipe[i]表示第i列是否有管道,1为有,0为没有,方便统计飞过的管道数
int Pipe_up[maxN];//Pipe_up[i]表示第i列上管道的高度,如果没有,置为m+1
int Pipe_down[maxN];//Pipe_down[i]表示第i列下管道的高度,如果没有,置为0
int F[2][maxM];//滚动动归 int main()
{
scanf("%d%d%d",&n,&m,&K);
memset(Pipe_up,0,sizeof(Pipe_up));
memset(Pipe_down,0,sizeof(Pipe_down));
memset(is_pipe,0,sizeof(is_pipe));
for (int i=0;i<n;i++)
scanf("%d%d",&X[i],&Y[i]);
for (int i=1;i<=n;i++)//将管道的信息初始化
{
Pipe_down[i]=0;
Pipe_up[i]=m+1;
}
for (int i=1;i<=K;i++)//读入管道
{
int pipe_pos,l,r;
scanf("%d%d%d",&pipe_pos,&l,&r);
Pipe_down[pipe_pos]=l;
Pipe_up[pipe_pos]=r;
is_pipe[pipe_pos]=1;
}
for (int i=1;i<=m;i++)//第0列初始化
F[0][i]=0;
int cnt=0;
int Ans;
for (int i=1;i<=n;i++)
{
int now=i&1;
Ans=inf;//这个Ans有两个用处,一是在最后一次统计答案,二是用来判断本次运算完后是否出现无解的情况
for (int j=0;j<=m;j++)//每一次先置为无穷大
F[now][j]=inf;
//cout<<Pipe_down[i]<<" "<<Pipe_up[i]<<endl; for (int j=X[i-1]+1;j<=m;j++)//先向上飞,注意循环初值
{
F[now][j]=min(F[!now][j-X[i-1]],F[now][j-X[i-1]])+1;
//cout<<F[!now][j-X[i-1]]<<endl;
} for (int j=m-X[i-1];j<=m;j++)//特判m的情况
{
F[now][m]=min(F[now][m],F[now][j]+1);
F[now][m]=min(F[now][m],F[!now][j]+1);
} for (int j=m-Y[i-1];j>=1;j--)//向下飞
F[now][j]=min(F[now][j],F[!now][j+Y[i-1]]); cnt+=(int)(is_pipe[i]);//统计管道数 for (int j=1;j<=m;j++)//统计当前最优解,如果是最后一列则是答案
{
if ((j<=Pipe_down[i])||(j>=Pipe_up[i]))
F[now][j]=inf;
Ans=min(Ans,F[now][j]);
}
if (Ans==inf)//如果Ans没有被更新,则说明此时无解,输出管道数。注意,因为无解的情况一定会出现在管道处,所以cnt-1
{
printf("0\n%d\n",cnt-1);
return 0;
}
/*
for (int j=1;j<=m;j++)
if (F[now][j]!=inf)
cout<<F[now][j]<<" ";
else
cout<<"i ";
cout<<endl;
//*/
}
printf("1\n%d\n",Ans);//如果有解,答案就在Ans里
return 0;
}

Luogu 1941 【NOIP2014】飞扬的小鸟 (动态规划)的更多相关文章

  1. LOJ2500 NOIP2014 飞扬的小鸟 【背包DP】*

    LOJ2500 NOIP2014 飞扬的小鸟 LINK 题目大意就是说有n个柱子,在每一秒你可以选择不点下降高度y和点p次上升x∗p,若果当前位置加上x∗p大于上界m,就会停在m. 如果可以成功穿越所 ...

  2. [NOIP2014]飞扬的小鸟[DP]

    [NOIP2014]飞扬的小鸟 ——!x^n+y^n=z^n 题目描述: Flappy Bird 是一款风靡一时的休闲手机游戏.玩家需要不断控制点击手机屏幕的频率来调节小鸟的飞行高度,让小鸟顺利通过画 ...

  3. NOIP2014 飞扬的小鸟

    3. 飞扬的小鸟 (bird.cpp/c/pas) [问题描述] Flappy Bird 是一款风靡一时的休闲手机游戏.玩家需要不断控制点击手机屏幕的频率来调节小鸟的飞行高度,让小鸟顺利通过画面右方的 ...

  4. vijos1907[noip2014]飞扬的小鸟(完全背包)

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

  5. [vijos1907][NOIP2014]飞扬的小鸟

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

  6. JZYZOJ1445 [noip2014day1-T3]飞扬的小鸟 动态规划 完全背包

    http://172.20.6.3/Problem_Show.asp?id=1445 很容易看出来动态规划的本质,但是之前写的时候被卡了一下(不止一下),还是写一下题解. 直接暴力O(n*m^2)大概 ...

  7. NOIP2014飞扬的小鸟

    长为n,高为m的二维平面,其中有k个管道(忽略管道的宽度)小鸟始终在游戏界面内移动.从最左边任意高度位置出发,到达游戏界面最右边,游戏完成每个单位时间沿横坐标方向右移距离为1,竖直移动的距离由玩家控制 ...

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

    坑人啊朴素的dp 75分 用了完全背包才是80分,结果普遍偏小 为什么啊啊啊啊啊 等以后再写一遍吧 #include<iostream> #include<cstdio> #i ...

  9. [NOIP2014]飞扬的小鸟 D1 T3 loj2500 洛谷P1941

    分析: 这是一个DP,没什么好说的,细节很烦人. DP[i][j]表示到第i个位置,高度为j点最少的次数. 转移: 当j=m时 k属于[m-h,m]都可以向DP[i][j]转移,即dp[i][j]=m ...

  10. luogu1941 [NOIp2014]飞扬的小鸟 (dp)

    设f[i][j]为到达(i,j)这个位置的最小操作数 就有$f[i][j]=min\{f[i-1][j+Y[i-1]],f[i-1][j-X[i-1]*k]+k\}$ 然后考虑优化一下转移: 对于一系 ...

随机推荐

  1. c++对象模型-对象模型

    1:简单对象模型 1>介绍:每个成员都使用一个指针指向真正的成员.所以对象 的大小很好确定,就是成员数*指针大小. 2>用途:成员函数就是使用这个模型的 3>图: 4>加上继承 ...

  2. Java 基础之一对象导论

    对象导论 1.1 抽象过程 所有编程语言都提供抽象机制.人们所能解决的问题的复杂性直接取决于抽象的类型和质量. 汇编语言是对底层机器的轻微抽象. 我们将问题空间中的元素及其再解空间中的表示称为对象.这 ...

  3. python-scapy学习笔记-(1)

    主要功能函数sniff sniff(filter="",iface="any",prn=function,count=N) filter参数允许我们对Scapy ...

  4. Centos6.5网络配置

    由于项目部署的需要,不得不继续研究Linux,前期看过一些Linux方面的资料,也动手配置过Linux网络配置,但是由于开发项目一般在windows下进行的,用Linux比较少,所以基本上也就忘记以前 ...

  5. 小学四则运算APP 最后阶段

    团队成员:陈淑筠.杨家安.陈曦 团队选题:小学四则运算APP 这次发布的是我们APP的最终版本!图片背景有根据用户需求改变!还增加了草稿纸运算的画布功能! 运行结果如下: package com.ex ...

  6. docker:Dockerfile构建LNMP平台

    docker:Dockerfile构建LNMP平台   1.dockerfile介绍  Dockerfile是Docker用来构建镜像的文本文件,包含自定义的指令和格式.可以通过docker buil ...

  7. Windows 聆听 简单使用体验

    1. 点击windows 按键 输入语音 按照操作 选择语音 并且读出那一段话. 2. 可以将windows 语音识别 添加到开始面板 3. 使用时 点击 该图标,然后点击麦克风按钮 聆听效果如图示 ...

  8. Oracle数据库SQLPLUS 连接显示 ??? 的解决

    linux下 安装了中文版本的,造成sqlplus 连接时出现了乱码 如图 一开始以为是LANG 变量的问题 后来发现是NLS_LANG的问题 解决方法: export NLS_LANG=" ...

  9. Qt__主窗口、菜单和工具条(QMainWindow,QMenu,QToolBar)

    转自豆子空间 主窗口 Qt的GUI程序有一个常用的顶层窗口,叫做MainWindow.MainWindow继承自QMainWindow.QMainWindow窗口分成几个主要的区域: 最上面是Wind ...

  10. 解决vmware与主机无法连通的问题

    我们选择NAT方式,来实现Ubuntu的静态IP地址配置. 打开VMware,在顶部依次选择:编辑 > 虚拟网路编辑器,打开虚拟网路编辑器:去掉VMnet0和VMnet1,只保留VMnet8.然 ...