飞扬的小鸟(背包)
Flappy Bird 是一款风靡一时的休闲手机游戏。玩家需要不断控制点击手机屏幕的频率来调节小鸟的飞行高度,让小鸟顺利通过画面右方的管道缝隙。如果小鸟一不小心撞到了水管或者掉在地上的话,便宣告失败。为了简化问题,我们对游戏规则进行了简化和改编:游戏界面是一个长为 n ,高为 m 的二维平面,其中有 k 个管道(忽略管道的宽度)。小鸟始终在游戏界面内移动。小鸟从游戏界面最左边任意整数高度位置出发,到达游戏界面最右边时,游戏完成。小鸟每个单位时间沿横坐标方向右移的距离为 1 ,竖直移动的距离由玩家控制。如果点击屏幕,小鸟就会上升一定高度 X ,每个单位时间可以点击多次,效果叠加;如果不点击屏幕,小鸟就会下降一定高度 Y 。小鸟位于横坐标方向不同位置时,上升的高度 X 和下降的高度 Y 可能互不相同。小鸟高度等于 0 或者小鸟碰到管道时,游戏失败。小鸟高度为 m 时,无法再上升。现在,请你判断是否可以完成游戏。如果可以,输出最少点击屏幕数;否则,输出小鸟最多可以通过多少个管道缝隙。
这道题就是一个01背包+完全背包的结合体TwT。注意特判天花板的情况即可
#include <cstdio>
using namespace std;
const int maxn=1e4+5, maxm=1e3+5, INF=1e9;
int inline min(int x, int y){ return x<y?x:y; }
int n, m, k, x[maxn], y[maxn], l[maxn], h[maxn], ans=INF, maxpip, pip[maxn];
int f[maxn][maxm]; //到达(x, y)最少点击次数
int main(){
scanf("%d%d%d", &n, &m, &k); int t1, flag;
for (int i=1; i<=n; ++i) scanf("%d%d", &x[i], &y[i]);
for (int i=1; i<=n; ++i) l[i]=0, h[i]=m+1;
for (int i=0; i<k; ++i){
scanf("%d", &t1); pip[t1]=1;
scanf("%d%d", &l[t1], &h[t1]); }
for (int i=1; i<=n; ++i){
for (int j=1; j<=m; ++j) f[i][j]=INF; flag=0;
for (int j=x[i]+1; j<m; ++j){ //当前点不是天花板,上一次跳跃的转移
f[i][j]=min(f[i][j], f[i-1][j-x[i]]+1);
f[i][j]=min(f[i][j], f[i][j-x[i]]+1); }
for (int j=m-x[i]; j<=m; ++j){ //特判
f[i][m]=min(f[i][m], f[i-1][j]+1);
f[i][m]=min(f[i][m], f[i][j]+1); }
for (int j=1; j<=m-y[i]; ++j)
f[i][j]=min(f[i][j], f[i-1][j+y[i]]);
for (int j=1; j<=l[i]; ++j) f[i][j]=INF;
for (int j=h[i]; j<=m; ++j) f[i][j]=INF;
for (int j=1; j<=m; ++j) if (f[i][j]!=INF) flag=1;
if (flag) maxpip+=pip[i];
}
for (int i=1; i<=m; ++i) ans=min(ans, f[n][i]);
if (ans!=INF) printf("1
%d
", ans); else printf("0
%d
", maxpip);
return 0;
}