[ NOIP ][ NOIP_2014D1T3 ][ 动态规划 ] 飞扬的小鸟

飞扬的小鸟(Flappy Bird)

描述

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

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

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

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

格式

输入格式

  第 1 行有 3 个整数 n,m,k,分别表示游戏界面的长度,高度和水管的数量,每两个 整数之间用一个空格隔开; 

  接下来的 n 行,每行 2 个用一个空格隔开的整数 X 和 Y,依次表示在横坐标位置 0~n-1 上玩家点击屏幕后,小鸟在下一位置上升的高度 X,以及在这个位置上玩家不点击屏幕时, 小鸟在下一位置下降的高度 Y。

  接下来 k 行,每行 3 个整数 P,L,H,每两个整数之间用一个空格隔开。每行表示一个管道,其中 P 表示管道的横坐标,L 表示此管道缝隙的下边沿高度为 L,H 表示管道缝隙上边沿的高度(输入数据保证 P 各不相同,但不保证按照大小顺序给出)。

输出格式

共两行。

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

样例1

样例输入1

10 10 6
3 9
6 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

(第三行 6 9 原为 9 9)

样例输出1

1
6

样例2

样例输入2

10 10 4
1 2
3 1
2 2
1 8
1 8
3 2
2 1
2 1
2 2
1 2
1 0 2
6 7 9
9 1 4
3 8 10

样例输出2

0
3

限制

  对于 30%的数据:5≤n≤10,5≤m≤10,k=0,保证存在一组最优解使得同一单位时间最多点击屏幕 3 次;

  对于 50%的数据:5≤n≤20,5≤m≤10,保证存在一组最优解使得同一单位时间最多点击屏幕 3 次;

  对于 70%的数据:5≤n≤1000,5≤m≤100;

  对于 100%的数据:5≤n≤10000,5≤m≤1000,0≤k<n,0<X<m,0<Y<m,0<P<n,0≤L<H ≤m,L+1<H。

提示

  如下图所示,蓝色直线表示小鸟的飞行轨迹,红色直线表示管道。

来源

NOIP2014 提高组 Day1

-------------------------------------------------------这里是华丽的分割线------------------------------------------------------------

定义:

  dp[i][j] 为 小鸟飞到坐标轴第 i 列第 j 行所需要点击的数目的最小值。

  枚举到了 i (i ∈ 1 ... n ) 和 j ( j ∈ 1 ... m) , 会遇到多个情况的状态转移。

  dp[i][j] 初始为∞, DOWN[i] : 第i列时自由下落的格子数, UP[i]:点击一下上升的格子数, HIGH[i]:空区域的上限(闭区间), LOW[i]相反。

情况一:从上一个格子不做操作自由落下

  当此情况合法时,有以下转移:

  dp[i][j] = min{dp[i][j], dp[i-1][j+DOWN[i-1]}

情况二:从上一列点击k次后上升

  此时问题转化为“背包容积为j,如何放无限个‘物品’(一次跳跃)使背包内物品价值最大”,即完全背包问题。

  dp[i][j] = min{dp[i][j], min{dp[i-1][j-UP[i-1]] + 1, dp[i][j-UP[i-1]] + 1}}

特殊情况: j 可能在屏幕最顶上(j == m),这时 i-1时的一段连续区间均转移到这个状态

  dp[i][m] = min{dp[i][m], min{dp[i-1][j] + 1, dp[i][j] + 1}}  j ∈ (m-UP[i-1] ... m)

其他细节:

  1.注意记录到当前i的所有柱子之和,当前dp[i][1...m]的最小值是否 < ∞ :是的话继续,不是的话输出无解跳出即可。

  2.注意区间开闭,先处理情况二,及时使dp[i][0...LOW[i]-1],dp[i][HIGH[i]+1 ... m] 为∞。

//Kvar_ispw17
#include <algorithm>
#include <sstream>
#include <cstring>
#include <cstdio>
#include <iostream>
using namespace std;
const int maxn = 10000 + 10;
const int inf = 0x7f7f7f7f;
int n, m, k, u[maxn], d[maxn], l[maxn], h[maxn], dp[maxn][1000 + 10]; bool kn[maxn];
int main() {
	freopen("bird.in", "r", stdin);
	scanf("%d%d%d", &n, &m, &k);
	for(int i = 0; i < n; i++) {
		scanf("%d%d", &u[i], &d[i]);
		h[i] = m, l[i] = 1;
	}
	h[n] = m, l[n] = 1;
	for(int i = 0; i < k; i++) {
		int x;
		scanf("%d", &x);
		scanf("%d%d", &l[x], &h[x]);
		kn[x] = 1, l[x]++, h[x]--;
	}
	static int _m;
	int cnt = 0;
	memset(dp, 0, sizeof dp);
	for(int i = 1; i <= n; i++) {
		for(int j = 1; j <= m; j++) {
			dp[i][j] = inf;
			if(j - u[i-1] >= 1) dp[i][j] = min(dp[i][j], min(dp[i-1][j - u[i-1]] + 1, dp[i][j - u[i-1]] + 1));
		}
		for(int j = m - u[i-1]; j <= m; j++) dp[i][m] = min(dp[i][m], min(dp[i-1][j] + 1,dp[i][j] + 1));
		for(int j = l[i]; j <= h[i]; j++) if(j + d[i-1] <= m) dp[i][j] = min(dp[i][j], dp[i-1][j + d[i-1]]);
		for(int j = 0; j < l[i]; j++) dp[i][j] = inf;
		for(int j = h[i] + 1; j <= m; j++) dp[i][j] = inf;
		_m = inf;
		for(int j = 1; j <= m; j++) _m = min(_m, dp[i][j]);
		if(_m >= inf) {
			printf("0\n%d\n", cnt);
			return 0;
		}
		if(kn[i]) cnt++;
	}
	printf("1\n%d\n", _m);
	return 0;
}
时间: 2024-12-19 14:16:11

[ NOIP ][ NOIP_2014D1T3 ][ 动态规划 ] 飞扬的小鸟的相关文章

[NOIP 2014TG D1T3] 飞扬的小鸟

题目描述 Flappy Bird 是一款风靡一时的休闲手机游戏.玩家需要不断控制点击手机屏幕的频率来调节小鸟的飞行高度,让小鸟顺利通过画面右方的管道缝隙.如果小鸟一不小心撞到了水管或者掉在地上的话,便宣告失败. 为了简化问题,我们对游戏规则进行了简化和改编: 游戏界面是一个长为n ,高为 m 的二维平面,其中有k 个管道(忽略管道的宽度). 小鸟始终在游戏界面内移动.小鸟从游戏界面最左边任意整数高度位置出发,到达游戏界面最右边时,游戏完成. 小鸟每个单位时间沿横坐标方向右移的距离为1 ,竖直移动

【UOJ #17】【NOIP 2014】飞扬的小鸟

http://uoj.ac/problem/17 dp,注意细节. #include<cstdio> #include<cstring> #include<algorithm> using namespace std; int in() { int k = 0, fh = 1; char c = getchar(); for(; c < '0' || c > '9'; c = getchar()) if (c == '-') fh = -1; for(; c

洛谷P1941 飞扬的小鸟 动态规划

洛谷P1941 飞扬的小鸟 动态规划 这道题主要要注意一下飞到m以上之后高度还是 m 这个就要在判断一下 比较直接暴力的动归 是 O(N^3) f[ i ][ j ] 到 i ,j 这个位置 所需要的最少点击次数 如果不能到,就是无限大 f[ i ][ j ] = min(f[ i-1 ][ j-up[i-1] ] +1 , f[ i-1 ][ j+down[i-1] ] ) 因为可以向上飞无限次 这其实就相当于是无限背包 然后 f[ i ][ j ] 就可以从 f[ i ][ j-up[ i-

luogu P1941 飞扬的小鸟

二次联通门 : luogu P1941 飞扬的小鸟 /* luogu P1941 飞扬的小鸟 dp 向上飞是完全背包,向下掉就是01背包 分情况讨论一下 最后合并一下 */ #include <cstdio> #include <iostream> #include <cstring> const int BUF = 123123123; char Buf[BUF], *buf = Buf; inline void read (int &now) { for (

洛谷 【P1941】飞扬的小鸟

P1941 飞扬的小鸟 题目描述 Flappy Bird 是一款风靡一时的休闲手机游戏.玩家需要不断控制点击手机屏幕的频率来调节小鸟的飞行高度,让小鸟顺利通过画面右方的管道缝隙.如果小鸟一不小心撞到了水管或者掉在地上的话,便宣告失败. 为了简化问题,我们对游戏规则进行了简化和改编: 游戏界面是一个长为n ,高为 m 的二维平面,其中有k 个管道(忽略管道的宽度). 小鸟始终在游戏界面内移动.小鸟从游戏界面最左边任意整数高度位置出发,到达游戏界面最右边时,游戏完成. 小鸟每个单位时间沿横坐标方向右

codevs 3729 飞扬的小鸟 x

3729 飞扬的小鸟 时间限制: 1 s 空间限制: 128000 KB 题目等级 : 黄金 Gold 题目描述 Description 输入描述 Input Description 输出描述 Output Description 输出文件名为 bird.out. 共两行. 第一行,包含一个整数,如果可以成功完成游戏,则输出 1,否则输出 0. 第二行,包含一个整数,如果第一行为 1,则输出成功完成游戏需要最少点击屏幕数, 否则,输出小鸟最多可以通过多少个管道缝隙. 样例输入 Sample In

noip2014飞扬的小鸟

飞扬的小鸟 题目链接 题意: 一个二维平面,长为\(n\),宽为\(m\),其中有\(k\)个管道,小鸟从最左边任意整数高度位置出发,到达游戏界面最右边时,游戏完成. 小鸟每个单位时间沿着\(x\)轴向右移动一个单位距离,小鸟在从\(i\)移动到\(i +1\)时,玩家可以选择是否点击屏幕(可以点击多次),若不点击,小鸟将下降\(y_i\)单位距离,若点击\(j\)次,小鸟的上升距离为\(j\times x_i\). 当小鸟碰到管壁或纵坐标等于\(0\)时,游戏结束.小鸟的高度可以不停上升,但最

NOIP 2014 飞扬的小鸟

描述 Flappy Bird 是一款风靡一时的休闲手机游戏.玩家需要不断控制点击手机屏幕的频率来调节小鸟的飞行高度,让小鸟顺利通过画面右方的管道缝隙.如果小鸟一不小心撞到了水管或者掉在地上的话,便宣告失败. 为了简化问题,我们对游戏规则进行了简化和改编: 游戏界面是一个长为 n,高为 m 的二维平面,其中有k 个管道(忽略管道的宽度). 小鸟始终在游戏界面内移动.小鸟从游戏界面最左边 任意整数高度位置出发,到达游戏界面最右边时,游戏完成. 小鸟每个单位时间沿横坐标方向右移的距离为 1,竖直移动的

【NOIP 2014 DAY1 T3】飞扬的小鸟(DP)

题目描述 Flappy Bird 是一款风靡一时的休闲手机游戏.玩家需要不断控制点击手机屏幕的频率来调节小鸟的飞行高度,让小鸟顺利通过画面右方的管道缝隙.如果小鸟一不小心撞到了水管或者掉在地上的话,便宣告失败. 为了简化问题,我们对游戏规则进行了简化和改编: 游戏界面是一个长为n ,高为 m 的二维平面,其中有k 个管道(忽略管道的宽度). 小鸟始终在游戏界面内移动.小鸟从游戏界面最左边任意整数高度位置出发,到达游戏界面最右边时,游戏完成. 小鸟每个单位时间沿横坐标方向右移的距离为1 ,竖直移动