Flappy Bird
是一款风靡一时的休闲手机游戏。玩家需要不断控制点击手机屏幕的频率来调节小鸟的飞行高度,让小鸟顺利通过画面右方的管道缝隙。如果小鸟一不小心撞到了水管或者掉在地上的话,便宣告失败。为了简化问题,我们对游戏规则进行了简化和改编:
游戏界面是一个长为 n,高为 m 的二维平面,其中有 k 个管道(忽略管道的宽度)。
小鸟始终在游戏界面内移动。小鸟从游戏界面最左边任意整数高度位置出发,到达游戏界面最右边时,游戏完成。
小鸟每个单位时间沿横坐标方向右移的距离为 1,竖直移动的距离由玩家控制。如果点击屏幕,小鸟就会上升一定高度 X,每个单位时间可以点击多次,效果叠加;如果不点击屏幕,小鸟就会下降一定高度 Y。小鸟位于横坐标方向不同位置时,上升的高度 X 和下降的高度 Y 可能互不相同。
小鸟高度等于 0 或者小鸟碰到管道时,游戏失败。小鸟高度为 m 时,无法再上升。
现在,请你判断是否可以完成游戏。如果可以,输出最少点击屏幕数;否则,输出小鸟最多可以通过多少个管道缝隙。
https://www.luogu.org/problemnew/show/P1941
很好想到f[i][j]表示走到(i,j)所需的最小步数。
同时很好想到状态转移方程:
f[i][j]=min(f[i][j],f[i-1][j-p*x[i-1]]+p),p>=1(因为在一个点可以再单位时间内点p次)
或者
f[i][j]=min(f[i][j],f[i-1][j+y[i-1]])(这表示自然下落)
以上很简单,但考虑的太少了
还要考虑到顶到顶了即j==m时的情况
来一个循环for(int z=m-x[i-1];z<=m;z++)
f[i][j]=min(f[i][j],f[i-1][z]+1)(走1步到顶)
f[i][j]=min(f[i][j],f[i][z]+1)(走2步或更多步到顶)
一个是i-1另一个是i,这个思想很重要。
也就是说你可以从这一行的下面转移到上面;
这个思想同样可以应用到之前那个式子的优化!!!
这个优化很重要!!
f[i][j]=min(f[i][j],f[i-1][j-p*x[i-1]]+p)
想一想,从f[3][1]到f[4][4]或者从f[3][1]到f[4][7],x[3]=3;
第一个按了一下,第二个按了两下;
是不是就等价于按一下从f[3][1]到f[4][4],再按一下从f[4][4]到f[4][7];
这样就得到了f[i][j]=min(f[i][j],f[i-1][j-x[i-1]]+1)和f[i][j]=min(f[i][j],f[i][j-x[i-1]]+1);
省去了p的枚举!!
至此此题再无难点~
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define inf 100000
using namespace std;
const int N=10001;
const int M=1001;
int inline read()
{
int x=0,f=1;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
return x*f;
}
int n,m,k,id;
int x[N],y[N];
int f[N][M];
int l[N],h[N];
bool p[N];
int main()
{
n=read();m=read();k=read();
for(int i=0;i<=n-1;i++){
x[i]=read();y[i]=read();
l[i]=0;h[i]=m+1;
}
l[n]=0;h[n]=m+1;
for(int i=1;i<=k;i++){
id=read();l[id]=read();h[id]=read();
p[id]=true;
}
for(int i=1;i<=n;i++)
{
for(int j=0;j<=m;j++)
{
f[i][j]=inf;
}
}
f[0][0]=inf;
for(int i=1;i<=m;i++){
f[0][i]=0;
}
for(int i=1;i<=n;i++){
for(int j=x[i-1];j<=m;j++){
if(j==m){
for(int z=m-x[i-1];z<=m;z++){
f[i][j]=min(f[i][j],f[i-1][z]+1);
f[i][j]=min(f[i][j],f[i][z]+1);
}
}
f[i][j]=min(f[i][j],f[i-1][j-x[i-1]]+1);
f[i][j]=min(f[i][j],f[i][j-x[i-1]]+1);
}
for(int j=max(1,l[i]+1);j<=min(m-y[i-1],h[i]-1);j++){
f[i][j]=min(f[i][j],f[i-1][j+y[i-1]]);
}
for(int j=l[i];j>=1;j--){
f[i][j]=inf;
}
for(int j=h[i];j<=m;j++){
f[i][j]=inf;
}
}
int ans=inf;
int cnt=k;
for(int i=n;i>=1;i--){
for(int j=l[i]+1;j<=h[i]-1;j++){
ans=min(ans,f[i][j]);
}
if(ans<inf){
break;
}
if(p[i]==true){
k--;
}
}
if(cnt==k){
cout<<1<<endl<<ans;
}
else{
cout<<0<<endl<<k;
}
return 0;
}