1644 免费馅饼(巴蜀oj上的编号)
题面:
SERKOI最新推出了一种叫做“免费馅饼”的游戏。
游戏在一个舞台上进行。舞台的宽度为W格,天幕的高度为H格,游戏者占一格。开始时,游戏者站在舞台的正中央,手里拿着一个托盘。
游戏开始后,从舞台天幕顶端的格子中不断出现馅饼并垂直下落。游戏者左右移动去接馅饼。游戏者每秒可以向左或右移动一格或两格,也可以站在愿地不动。
馅饼有很多种,游戏者事先根据自己的口味,对各种馅饼依次打了分。同时在8-308电脑的遥控下,各种馅饼下落的速度也是不一样的,下落速度以格/秒为单位。当馅饼在某 一秒末恰好到达游戏者所在的格子中,游戏者就收集到了这块馅饼。
写一个程序,帮助我们的游戏者收集馅饼,使得收集的馅饼的分数之和最大。
输入数据:
第一行:宽度W(1~99奇数)和高度H(1 ~ 100整数)
接下来给出了一块馅饼信息。由4个正整数组成,分别表示了馅饼的初始下落时刻、水平位置、下落速度、分值。
游戏开始时刻为0。从1开始自左向右依次对水平方向的每格编号。
输出数据:
收集到的馅饼最大分数之和。
——————————————分割线————————————————————————————————————————————————————
题解:
由于馅饼下落的时间和速度都不同,人只能向左右移动,馅饼只能向下移动。人和馅饼都同时移动,思考起来比较复杂,因此我们需要转变思路:
算出每个时刻落到最底层的每个格子有多少分值的馅饼。
如果将馅饼当成参照物,则馅饼向下落,可以看成馅饼不动,人往上走去摘取馅饼,这样人每1时刻都可以走到上一行的5个格子,
这道题是经典动规模型数塔的变形,将馅饼落下的位置看做数塔中的列数,将下落的时间看做数塔中的行数,问题转化为求解从塔底到塔顶的最长路径。
计算出每个格子每个时刻可能达到的馅饼分值,填入W*H的天幕表。
代码:
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
using namespace std;
int w,h;
struct pie
{
int time,pos,speed,value,t;
}s[10001];//用结构体来记录数据
int f[1001][1001];//记录决策
int main()
{
cin>>w>>h;
int n=1,ss,maxn=-999,ans=0;
//while (scanf("%d%d%d%d",s[n].time,s[n].pos,s[n].speed,s[n].value)==4)
while (cin>>s[n].time>>s[n].pos>>s[n].speed>>s[n].value)//由于不知道数据个数,用while读入
{
s[n].t=ceil(h/s[n].speed)+s[n].time;//t指该馅饼下落下来(到最后一格)的时间
n++;//这一步核心意思就是将该时间取整,但是是加一位(2.....=3)
}
n-=1;//n为馅饼个数
for (int i=1;i<=n;i++)
{
f[s[i].pos][s[i].t]+=s[i].value;
maxn=max(s[i].t,maxn);//找到最晚的馅饼的时间
}
for (int j=maxn-1;j>=0;j--)
for (int i=1;i<=w;i++)
{
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;//状态转移方程应用
}
cout<<f[w/2+1][0];//由于人以中间为起点,所以输出(w/2+1,0)
return 0;
}
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
using namespace std;
int w,h;
struct pie
{
int time,pos,speed,value,t;
}s[10001];//用结构体来记录数据
int f[1001][1001];//记录决策
int main()
{
cin>>w>>h;
int n=1,ss,maxn=-999,ans=0;
//while (scanf("%d%d%d%d",s[n].time,s[n].pos,s[n].speed,s[n].value)==4)
while (cin>>s[n].time>>s[n].pos>>s[n].speed>>s[n].value)//由于不知道数据个数,用while读入
{
s[n].t=ceil(h/s[n].speed)+s[n].time;//t指该馅饼下落下来(到最后一格)的时间
n++;//这一步核心意思就是将该时间取整,但是是加一位(2.....=3)
}
n-=1;//n为馅饼个数
for (int i=1;i<=n;i++)
{
f[s[i].pos][s[i].t]+=s[i].value;
maxn=max(s[i].t,maxn);//找到最晚的馅饼的时间
}
for (int j=maxn-1;j>=0;j--)
for (int i=1;i<=w;i++)
{
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;//状态转移方程应用
}
cout<<f[w/2+1][0];//由于人以中间为起点,所以输出(w/2+1,0)
return 0;
}