题目描述:
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;
}