noip2014 提高组题解 bird
来源:互联网 发布:算法工程师怎么考 编辑:程序博客网 时间:2024/06/05 15:18
题目描述:
Flappy Bird 是一款风靡一时的休闲手机游戏。玩家需要不断控制点击手机屏幕的频率来调节小鸟的飞行高度,让小鸟顺利通过画面右方的管道缝隙。如果小鸟一不小心撞到了水管或者掉在地上的话,便宣告失败。 为了简化问题,我们对游戏规则进行了简化和改编:
1. 游戏界面是一个长为n ,高为 m 的二维平面,其中有k 个管道(忽略管道的宽度)。
2. 小鸟始终在游戏界面内移动。小鸟从游戏界面最左边任意整数高度位置出发,到达游戏界面最右边时,游戏完成。
3. 小鸟每个单位时间沿横坐标方向右移的距离为1 ,竖直移动的距离由玩家控制。如果点击屏幕,小鸟就会上升一定高度X ,每个单位时间可以点击多次,效果叠加;如果不点击屏幕,小鸟就会下降一定高度Y 。小鸟位于横坐标方向不同位置时,上升的高度X 和下降的高度Y 可能互不相同。
4. 小鸟高度等于0 或者小鸟碰到管道时,游戏失败。小鸟高度为 m 时,无法再上升。
现在,请你判断是否可以完成游戏。如果可以 ,输出最少点击屏幕数;否则,输出小鸟最多可以通过多少个管道缝隙。
【输入】
输入文件名为 bird.in 。
第1 行有3 个整数n ,m ,k ,分别表示游戏界面的长度,高度和水管的数量,每两个整数之间用一个空格隔开; 接下来的n 行,每行2 个用一个空格隔开的整数X 和Y ,依次表示在横坐标位置0 ~n- 1上玩家点击屏幕后,小鸟在下一位置上升的高度X ,以及在这个位置上玩家不点击屏幕时,小鸟在下一位置下降的高度Y 。
接下来k 行,每行3 个整数P ,L ,H ,每两个整数之间用一个空格隔开。每行表示一个管道,其中P 表示管道的横坐标,L 表示此管道缝隙的下边沿高度为L ,H 表示管道缝隙上边沿的高度(输入数据保证P 各不相同,但不保证按照大小顺序给出)。
【输出】
输出文件名为bird.out 。
共两行。
第一行,包含一个整数,如果可以成功完成游戏,则输出1 ,否则输出0 。
第二行,包含一个整数,如果第一行为1 ,则输出成功完成游戏需要最少点击屏幕数,否则,输出小鸟最多可以通过多少个管道缝隙。
解题思路:
首先在考场的时候看到这到题目脑子抽了,竟然没有想出来,然后出来后无聊时灵光一闪就想出来了(我TM真是。。。车啊。。。。。)
说实话我不知道30分和50分应该怎么做,估计搜索吧。。。。。。。,这道题目需要对水管的横坐标进行排序我就不说了
1、70分:
很裸的dp,定义状态f[i][j]为小鸟飞到(i,j)时所需要的最小的步数,转移方程应该很好写,如果写不出我也没办法了,估计你没学过dp(好像广搜TMD也可以。。。。艹)
2、100分
就是贴吧大神们说的下落做0,1背包,上升做无限背包(虽然当时我想出来正解是竟然不知道这TM是背包。。。。。果然我是蒟蒻。。。。。。。。。)
我们需要一些数组,f[i][j]表示小鸟飞到(i,j)是所需要的最小的步数,k[i][j]表示从i-1点击屏幕上升过来需要的最小步数(即在转移k[i][j]是必须要从f[i-1][t],(t<j)转移过来)
如果用change[i].up表示从i-1到i点击一下屏幕的上升的高度,change[i].down表示从i-1到i下落的高度(边界条件请读者自己考虑)
那么f[i][j]=MIN(f[i-1][j-change[i].up]+1, k[i][j-change[i].up]+1, f[i-1][j+change[i].down]) (转移时不需要考虑(i,j)是否是管子,只需要考虑转移过来的点是不是管子)
f[i-1][j-change[i].up], k[i][j-change[i].up], f[i-1][j+change[i].down]中没意义的就不用考虑了
对于 f[i-1][j-change[i].up] 来说,没有意义就是达不到(i-1,j-change[i].up)或者(i-1,j-change[i].up)是水管
对于k[i][j-change[i].up]来说,没有意义就是在i-1通过点击屏幕上升达不到(i,j-change[i].up)
对于f[i-1][j+change[i].down]来说,没有意义就是达不到(i-1,j+change[i].down)或者(i-1,j+change[i].down)是水管
这样我们就可以将时间复杂度降到O(nm),AC妥妥的。。。。。。
那么如何判断无解呢?很简单,当i为某水管的横坐标时,只需要判断是不是对于所在管子的L,H间的存在一个点使得小鸟可以飞到,如果不存在就直接输出(当前管子编号-1)
证明我就不啰嗦了(其实我是不会哈哈哈哈哈。。。。。。。。)脑补吧。。。。。。。我知道各位都是大神
提醒:
上述做法还需要用一个数组判断f[i][j]是否可以达到,或者你可以将f[i][j]的初值赋为-1,k不需要,因为k要求从i-1点击一次到i那么他的点击数一定大于0,故不需要
//本人是淳朴的C党#include <stdio.h>#include <stdlib.h>#include <math.h>#include <string.h>#define MAX(a,b) (a>b?a:b)#define MIN(a,b) (a>b?b:a)struct guan{ int x; int up; int down;}g[10010]={0};int change[10010][4]={0};int f[10010][1010]={0};int hash[10010][1010]={0};int t[10010][1010]={0};int k[10010][1010]={0};int n,m,e;void px(int l,int r){ int i=l,j=r; struct guan t=g[l]; for(;i<j;) { for(;i<j;j--) if(t.x>g[j].x) { g[i]=g[j]; break; } for(;i<j;i++) if(t.x<g[i].x) { g[j]=g[i]; break; } } g[i]=t; if(i>l) px(l,i-1); if(i<r) px(i+1,r); return;}int main(){ int i,j,p,q; int o=0; freopen("bird.in","r",stdin); freopen("bird.out","w",stdout); scanf("%d%d%d",&n,&m,&e); for(i=1;i<=n;i++) scanf("%d%d",&change[i][1],&change[i][2]); for(i=1;i<=e;i++) scanf("%d%d%d",&g[i].x,&g[i].down,&g[i].up); px(1,e); for(i=1;i<=m;i++) t[0][i]=1; for(i=1,p=1;i<=n;i++) { o=0; if(i>g[p].x) p++; if(i==g[p].x) { for(j=0;j<=g[p].down;j++) hash[i][j]=1; for(j=g[p].up;j<=m;j++) hash[i][j]=1;}for(j=1;j<=m;j++){if(j-change[i][1]>=1){if(hash[i-1][j-change[i][1]]==0 && t[i-1][j-change[i][1]]==1){f[i][j]=f[i-1][j-change[i][1]]+1;t[i][j]=1;k[i][j]=f[i-1][j-change[i][1]]+1;if(hash[i][j]==0)o=1;}if(t[i][j-change[i][1]]==1 && k[i][j-change[i][1]]>0){if(t[i][j]==1){f[i][j]=MIN(f[i][j],k[i][j-change[i][1]]+1);k[i][j]=MIN(k[i][j],k[i][j-change[i][1]]+1);}else{f[i][j]=k[i][j-change[i][1]]+1;k[i][j]=k[i][j-change[i][1]]+1;t[i][j]=1;if(hash[i][j]==0)o=1;}}}if(j+change[i][2]<=m){if(hash[i-1][j+change[i][2]]==0 && t[i-1][j+change[i][2]]==1){if(t[i][j]==0){f[i][j]=f[i-1][j+change[i][2]];t[i][j]=1;if(hash[i][j]==0)o=1;}else f[i][j]=MIN(f[i][j],f[i-1][j+change[i][2]]);}}}for(j=m-change[i][1]+1;j<=m;j++){if(hash[i-1][j]==0 && t[i-1][j]==1){if(t[i][m]==0){f[i][m]=f[i-1][j]+1;t[i][m]=1;k[i][m]=f[i-1][j]+1;if(hash[i][m]==0)o=1;}else{f[i][m]=MIN(f[i][m],f[i-1][j]+1);k[i][m]=MIN(k[i][m],f[i-1][j]+1);}}if(t[i][j]==1 && k[i][j]>0){if(t[i][m]==1){f[i][m]=MIN(f[i][m],k[i][j]+1);k[i][m]=MIN(k[i][m],k[i][j]+1);}else{f[i][m]=f[i][j]+1;k[i][m]=k[i][j]+1;t[i][m]=1;if(hash[i][m]==0)o=1;}}} if(o==0) { printf("0\n%d",p-1); fclose(stdin); close(stdout); return 0; } } j=2e9; for(i=1;i<=m;i++) if(t[n][i]==1) j=MIN(j,f[n][i]); printf("1\n%d",j); fclose(stdin); fclose(stdout); return 0;}
- noip2014 提高组题解 bird
- NOIP2014提高组DAY1题解
- noip2014 提高组题解 equation
- noip2014 提高组题解 link
- noip2014 提高组题解 road
- [题解]NOIP2014提高组の题解集合
- noip2014提高组day2二题题解-rLq
- noip2014普及组题解
- NOIP2014提高组初赛
- NOIP2014提高组解析
- NOIP2014提高组Day2
- NOIP2014提高组模拟8.9
- NOIP2014提高组 寻找道路
- NOIP2014提高组解方程
- NOIP2014提高组 DAY1 -SilverN
- NOIP2014 提高组 寻找道路
- Noip2014题解
- NOIP2014题解
- JAVA内存详解
- 关于系统权限设计的思考
- Tornado依据header收集用户信息
- 转——java调用.so文件的例子
- 链栈的实现
- noip2014 提高组题解 bird
- iOS-UITableView分页加载
- flash的坐标系详解
- web压力测试-pylot
- HDU2527 Safe Or Unsafe 哈夫曼编码
- 调用快排
- assets目录下的文件拷贝到sd卡目录下
- js弹出框、对话框、提示框、弹窗总结
- 【opencv+C++】在图像中找四边形