标签:
3. 飞扬的小鸟
(bird.cpp/c/pas)
【问题描述】
Flappy Bird 是一款风靡一时的休闲手机游戏。玩家需要不断控制点击手机屏幕的频率来调节小鸟的飞行高度,让小鸟顺利通过画面右方的管道缝隙。如果小鸟一不小心撞到了水管或者掉在地上的话,便宣告失败。
为了简化问题,我们对游戏规则进行了简化和改编:
现在,请你判断是否可以完成游戏。如果可以,输出最少点击屏幕数;否则,输出小鸟
最多可以通过多少个管道缝隙。
【输入】
输入文件名为 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,则输出成功完成游戏需要最少点击屏幕数,否则,输出小鸟最多可以通过多少个管道缝隙。
【输入输出样例1】
bird.in |
bird.out |
10 10 6 3 9 9 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 |
1 6 |
【输入输出样例2】
bird.in |
bird.out |
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 |
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。
【思路】
题目思路很简单,但是写起来总感觉不顺手。
状态转移方程:
D[i][j]=min{d[i-1][j+y[i-1], d[i-1][j-k*x[i-1]+k}
这里的k容易联想到完全背包的无限物品,类似的,不用去枚举k,改成d[i][j-x[i]]+1,它的意思其实就是累计。修改之后还需要注意由y划分子问题应该放在x之后,否则会造成决策叠加的效果。
J==m的特殊情况:注意到题目中说“小 鸟 高 度 为m时,无法再上升。”特殊处理:也是用累计的方法,d[i][j]=min(d[i][j],d[i][pos]+1) pos from [j-x[i-1],m] 由点成为了线段。
Fly失败:用一个flag,只要d[i][]全都为INF则问题不能求解,相应输出结束。
【代码】
1 #include<iostream> 2 #define FOR(a,b,c) for(int a=(b);a<(c);a++) 3 using namespace std; 4 5 const int INF=1<<30; 6 const int maxn = 10000 + 5, maxm = 1000+5; 7 int n,m,K; 8 int d[maxn][maxm]; 9 int x[maxn],y[maxn],up[maxn],down[maxn]; 10 11 int main() { 12 ios::sync_with_stdio(false); 13 14 cin>>n>>m>>K; 15 FOR(i,0,n) { 16 cin>>x[i]>>y[i]; 17 up[i]=m+1; down[i]=0; //down=0 up=m+1 18 } up[n]=m+1; down[n]=0; 19 20 FOR(i,0,K) { 21 int p; cin>>p; 22 cin>>down[p]>>up[p]; 23 } 24 FOR(i,1,n+1) FOR(j,0,m+1) d[i][j]=INF; 25 d[0][0]=INF;//d声明在全局变量自动清0 26 27 FOR(i,1,n+1) //i从1开始 到n结束 28 { 29 bool flag=true; 30 FOR(j,down[i]+1,up[i]) { //这里写错过== 31 if(j-x[i-1]>down[i-1]) { 32 d[i][j]=min(d[i][j],d[i][j-x[i-1]]+1); 33 d[i][j]=min(d[i][j],d[i-1][j-x[i-1]]+1); 34 } 35 if(j==m) FOR(pos,j-x[i-1],j+1) { //特殊情况特殊判断//注意不要写在上一个if里 36 d[i][j]=min(d[i][j],d[i][pos]+1); 37 d[i][j]=min(d[i][j],d[i-1][pos]+1); 38 } 39 if(d[i][j]<INF) flag=false; 40 } 41 //求完关于x之后才能求y 否则x中的决策d[i][j-x[i]]可能会转移到y中求过的状态 造成既下降又上升的情况 42 FOR(j,down[i]+1,up[i]) if(j+y[i-1]<up[i-1]) { 43 d[i][j]=min(d[i][j],d[i-1][j+y[i-1]]); 44 if(d[i][j]<INF) flag=false; 45 } 46 47 if(flag) { //如果本i不能通过那么output退出 48 int sum=0; 49 FOR(k,0,i) 50 if(up[k]!=m+1 || down[k]!=0) sum++; //如果是管道 //||而非&& 51 cout<<0<<"\n"<<sum; 52 return 0; 53 } 54 } 55 56 int mini=INF; 57 FOR(j,1,m+1) mini=min(mini,d[n][j]); //最右边为n 58 cout<<1<<"\n"<<mini; 59 return 0; 60 61 }
标签:
原文地址:http://www.cnblogs.com/lidaxin/p/4859276.html