免费馅饼
SERKOI最新推出了一种叫做“免费馅饼”的游戏:游戏在一个舞台上进行。舞台的宽度为W格,天幕的高度为H格,游戏者占一格。开始时游戏者站在舞台的正中央,手里拿着一个托盘。下图为天幕的高度为4格时某一个时刻游戏者接馅饼的情景。
游戏开始后,从舞台天幕顶端的格子中不断出现馅饼并垂直下落。游戏者左右移动去接馅饼。游戏者每秒可以向左或向右移动一格或两格,也可以站在原地不动。
馅饼有很多种,游戏者事先根据自己的口味,对各种馅饼依次打了分。同时,在8-308电脑的遥控下,各种馅饼下落的速度也是不一样的,下落速度以格/秒为单位。
当馅饼在某一秒末恰好到达游戏者所在的格子中,游戏者就收集到了这块馅饼。
写一个程序,帮助我们的游戏者收集馅饼,使得所收集馅饼的分数之和最大。
输入
输入文件的第一行是用空格隔开的两个正整数,分别给出了舞台的宽度W(1到99之间的奇数)和高度H(1到100之间的整数)。
接下来依馅饼的初始下落时间顺序给出了所有馅饼的信息。每一行给出了一块馅饼的信息。由四个正整数组成,分别表示了馅饼的初始下落时刻(0到1000秒),水平位置、下落速度(1到100)以及分值。游戏开始时刻为0。从1开始自左向右依次对水平方向的每格编号。
输入文件中同一行相邻两项之间用一个或多个空格隔开。
输出
输出文件的第一行给出了一个正整数,表示你的程序所收集的最大分数之和。
样例输入
3 3
0 1 2 5
0 2 1 3
1 2 1 3
1 3 1 4
样例输出
12
说在前面:首先,这道题目的想法思路是XYX大爷想出来的,我只是觉得这个方法很神,所以就发上来了,所以本文作者实际上是XYX大爷。
————————————分分分割线——————————————
解题思路:简单来说就是建立一个时空坐标轴,通过馅饼的下落速度与起始时间来确定馅饼的坐标,以时间为Y轴,舞台宽度为X轴,每次向上走一格,转化成类似数字三角形的方法就可以了(我问XYX大爷你怎么想到转时间为坐标轴的,他说他从小就喜欢这么干(:з」∠))
代码:
#include<cstdio>
#include<iostream>
using namespace std;
int w,h;
struct os
{
int time,pos,speed,value,t;
}a[10001];
int f[1000][100],zb[1000][100];
main()
{
scanf("%d%d",&w,&h);
int n=1;
while (cin>>a[n].time>>a[n].pos>>a[n].speed>>a[n].value)
{
a[n].t+=((h-2+a[n].speed)/a[n].speed)+a[n].time;//t指该馅饼下落下来(到最后一格)的时间
//这一步比较难理解,核心意思就是将该时间取整,但是是加一位(2.....=3)我试过用我自己的方法取整,但只过了60%(╰_╯)#
n++;
}
n--;
int maxn=-999;
for (int i=1;i<=n;i++)
{
f[a[i].pos][a[i].t]+=a[i].value;
maxn=max(a[i].t,maxn);//找到最晚的馅饼的时间
}
for (int j=maxn-1;j>=0;j--)
for (int i=1;i<=w;i++)
{
//进行dp寻找
int ans=0;
if (f[i-2][j+1]&&i-2>0)
ans=max(ans,f[i-2][j+1]);
if (f[i-1][j+1]&&i>1)
ans=max(ans,f[i-1][j+1]);
if (f[i][j+1])
ans=max(ans,f[i][j+1]);
if (f[i+2][j+1]&&i+2<=w)
ans=max(ans,f[i+2][j+1]);
if (f[i+1][j+1]&&i+1<=w)
ans=max(ans,f[i+1][j+1]);
f[i][j]+=ans;
}
printf("%d",f[w/2+1][0]);//由于人以中间为起点,所以输出(w/2+1,0)
}