题目
都说天上不会掉馅饼,但有一天gameboy正走在回家的小径上,忽然天上掉下大把大把的馅饼。说来gameboy的人品实在是太好了,这馅饼别处都不掉,就掉落在他身旁的10米范围内。馅饼如果掉在了地上当然就不能吃了,所以gameboy马上卸下身上的背包去接。但由于小径两侧都不能站人,所以他只能在小径上接。由于gameboy平时老呆在房间里玩游戏,虽然在游戏中是个身手敏捷的高手,但在现实中运动神经特别迟钝,每秒种只有在移动不超过一米的范围内接住坠落的馅饼。现在给这条小径如图标上坐标:
为了使问题简化,假设在接下来的一段时间里,馅饼都掉落在0-10这11个位置。开始时gameboy站在5这个位置,因此在第一秒,他只能接到4,5,6这三个位置中其中一个位置上的馅饼。问gameboy最多可能接到多少个馅饼?(假设他的背包可以容纳无穷多个馅饼)
Input
输入数据有多组。每组数据的第一行为以正整数n(0<n<100000),表示有n个馅饼掉在这条小径上。在结下来的n行中,每行有两个整数x,T(0<T<100000),表示在第T秒有一个馅饼掉在x点上。同一秒钟在同一点上可能掉下多个馅饼。n=0时输入结束。
Output
每一组输入数据对应一行输出。输出一个整数m,表示gameboy最多可能接到m个馅饼。
提示:本题的输入数据量比较大,建议用scanf读入,用cin可能会超时。
Input
6
5 1
4 1
6 1
7 2
7 2
8 3
0
Output
4
思路
初始状态,dp[i][j]表示在 i 时刻,j 这个位置可以接到馅饼的最大数目,根据输入先填上初始值。
接下来有两种思路:1. 比较直观的一种就是从上往下填,dp[i+1][j]可以由dp[i+1][j] + max(dp[i][j-1], dp[i][j], dp[i][j+1])得到,即第i+1秒,可以从上一秒的三个位置出发达到,然后选个最大的位置出发,这样每个时刻都得到一个点的最优解,最后填完所有表,在最后一行找一个最大值就可以。但是问题是,从0秒开始,不是所以点都是可以到达的,比如第一秒不可能走到4、5、6以外的点,所以此时这些点的空格不可以根据上一秒的结果来填,如果要计算从0秒开始可以到达的范围,即什么时候开始可以按上一秒填,会很复杂。
2. 于是有第二种思路,从下往上填,初始状态不变,假设总共m行,从m-1行开始填,dp[i][j] = dp[i][j] + max(dp[i+1][j-1], dp[i+1][j], dp[i+1][j+1]),即按照下一秒可以到达的三个位置,选最大的,作为这一秒的最优选择,这样,第i秒的决策做好了,然后再做i-1秒的决策。最终填完第一行之后,直接返回dp[0][5]即可,因为这是初始的位置。感觉上倒着填稍微多做了一些不必要的计算,但避免了计算哪些可以达到,哪些不能达到的麻烦。
这种从下往上填的好像是第一次见。抽象一点的感觉是,这个过程的状态如果用s1,s2,s3...sn表示,它不是从s1开始每一步都做最好的决策,而是先算s n-1到sn的决策,然后再算s n-2到s n-1,总体上是倒着算的决策过程。
参考:https://blog.csdn.net/qq_36459536/article/details/78932397