免费馅饼
Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others)Total Submission(s): 18793 Accepted Submission(s): 6283
为了使问题简化,假设在接下来的一段时间里,馅饼都掉落在0-10这11个位置。开始时gameboy站在5这个位置,因此在第一秒,他只能接到4,5,6这三个位置中其中一个位置上的馅饼。问gameboy最多可能接到多少个馅饼?(假设他的背包可以容纳无穷多个馅饼)
提示:本题的输入数据量比较大,建议用scanf读入,用cin可能会超时。
6 5 1 4 1 6 1 7 2 7 2 8 3 0
<解题分析>
据题意,当我们第T秒站在x点的时候,我们便可以在T+1秒的时候接到x-1,x,x+1这三个点其中的一个点的馅饼。
假设我们第T秒站在了x点,那么直到结束时最多能接到多少个馅饼呢?将其记为
DP(T,x)。
而将在T秒站在x点正接到的馅饼数记为
exactly(T,x)。
那么下一秒,即T+1秒就有可能站在x、x-1、 x+1这三个点之中的一个点,有方程:
DP[T,x]= exactly[T,x]+ MAX( DP(T+1,x), DP[T+1,x-1], DP[T+1,x+1]) (式1)
假设最后一个馅饼会在第END秒掉下,那么我们可知
DP(END,x)= exactly(END,x) (式2)
我们从最后一秒看起,第一步知道了每一个点在EDN秒的exactly值,也就是DP值,下一步就可以求出每一个点在END-1秒的DP值,以此往前推算,最终可以求出所有点在第0秒的DP值,依题设中开始位置在5,那么DP(0,5)就是所求答案,即最多可能接到馅饼数。
我们把式1叫做状态转移方程,式2叫做初值表达式。
样例求解过程:
6
5 1
4 1
6 1
7 2
7 2
8 3
本例首先可知END=3和exactly值,
exactly值
X T | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 |
3 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 0 |
2 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 2 | 0 | 0 |
1 | 0 | 0 | 0 | 0 | 1 | 1 | 1 | 0 | 0 | 0 |
0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
接下来可依次求解各秒的DP值
X T | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 |
3 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 0 |
2 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 3 | 1 | 1 |
1 | 0 | 0 | 0 | 0 | 1 | 1 | 4 | 3 | 3 | 1 |
0 | 0 | 0 | 0 | 1 | 1 | 4 | 4 | 4 | 3 | 3 |
第三秒时,DP[3,8]=0,这一行的其它值都是0,
第二秒时, DP[2,7]= exactly[2,7]+max(DP[2,6],DP[2,7],DP[2,8])=2+max(0,0,1)=2+1=3。
其它的值也都是这样根据式2计算出来,最后计算到第0秒就结束了。
AC代码:
#include<iostream>
const int MAX=100001;
int DP[MAX][12];//保存第 i秒 j 位置 最多还能接到的馅饼
int Now[MAX][12];//保存第 i秒 j 位置落下的馅饼
using namespace std;
int main()
{
int n,pos,time,i,Time_MAX,maxn;
while(scanf("%d",&n)&&n)
{
memset(DP,0,sizeof(DP));
memset(Now,0,sizeof(Now));
Time_MAX=0;
for(i=0;i<n;i++)
{
//cin>>pos>>time;
scanf("%d%d",&pos,&time);
Now[time][pos]+=1;
if(Time_MAX<time)
{
Time_MAX=time;
}
}
for(i=0;i<=10;i++)
{
DP[Time_MAX][i]=Now[Time_MAX][i];
}
for(time=Time_MAX-1;time>=0;time--)
{
for(pos=0;pos<=10;pos++)
{
maxn=0;
if(pos>=1)
maxn=DP[time+1][pos-1];
if(DP[time+1][pos]>maxn)
maxn=DP[time+1][pos];
if(pos<=9&&DP[time+1][pos+1]>maxn)
maxn=DP[time+1][pos+1];
DP[time][pos]=Now[time][pos]+maxn;
}
}
printf("%d\n",DP[0][5]);
//cout<<DP[0][5]<<endl;
}
return 0;
}