中文题,题目描述不再多说,直接说思路。
首先是状态转移,用dp[ i ][ j ]表示第 i 时刻在第 j 位置能接到的最大馅饼数目,状态来源有三
- 上一时刻左边位置转移过来
- 上一时刻右边位置转移过来
- 上一时刻当前位置转移过来
因此我们得出了状态的转移过程,有一个问题在于,如何存放输入的数据能方便我们计算呢
如果我们用一个二维数组a[ i ][ j ]表示在 i 时刻有 j 个馅饼掉落,将数组初始化为0,对于输入每一个时刻每一个位置,每次执行自增操作即可,这样在写状态转移方程的时候就会方便很多(方法是借鉴大佬的,orzorz)
还有一个小细节,就是我们并不知道我们的终点实在哪个时刻哪个位置,如果正向进行的话我们需要规定一个时刻,去便利最终时刻的所有位置求最大值,但是如果我们逆向进行循环就不用那么多顾虑,因为我们的起点是已知的,最后直接输出 0 时刻起点的值即可
由此可以得到状态转移方程
dp[i][j] = dp[i + 1][j] + a[i + 1][j];
if(j >= 1) dp[i][j] = max(dp[i][j], dp[i + 1][j - 1] + a[i + 1][j - 1]);
if(j <= 9) dp[i][j] = max(dp[i][j], dp[i + 1][j + 1] + a[i + 1][j + 1]);
完整代码:
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#include <cmath>
#include <queue>
using namespace std;
const int maxn = 1e5 + 10;
int n, x, t;
int dp[maxn][11], a[maxn][11];
int main()
{
while (~scanf("%d", &n) && n){
memset(dp, 0, sizeof dp);
memset(a, 0, sizeof a);
for (int i = 1; i <= n; i++){
scanf("%d %d", &x, &t);
a[t][x]++;
}
for (int i = maxn - 10; i >= 0; i--){
for (int j = 0; j <= 10; j++){
dp[i][j] = dp[i + 1][j] + a[i + 1][j];
if(j >= 1) dp[i][j] = max(dp[i][j], dp[i + 1][j - 1] + a[i + 1][j - 1]);
if(j <= 9) dp[i][j] = max(dp[i][j], dp[i + 1][j + 1] + a[i + 1][j + 1]);
}
}
printf("%d\n", dp[0][5]);
}
return 0;
}