原題見這裏
關於解題的詳細步驟都已經在代碼註釋裏面了,這裏一定要注意,剛開始gameboy在位置5,因此在第5秒鐘之前,他的活動範圍有限,所以,在循環的時候j的範圍不一定能從0到10
#include <iostream>
using namespace std;
int a[100001][11];
int dp[2][11];
int main() {
//dp[i][j]表示第i秒鐘在位置j獲得的最多的餅
//a[i][j]表示第i秒鐘在位置j落下的餅的數量
//那麼求解dp[i][j]的時候,分三種情況
//1.第i-1秒在j-1 或0 dp[i][j] = dp[i-1][j-1] + a[i][j]
//2.第i-1秒在j dp[i][j] = dp[i-1][j] + a[i][j]
//3.第i-1秒在j+1 或10 dp[i][j] = dp[i-1][j+1] + a[i][j]
//那麼狀態轉移方程爲 dp[i][j] = max(dp[i-1][j-1], dp[i-1][j], dp[i-1][j+1]) + a[i][j];
//優化 每一次只用到了i-1的信息,因此可以優化哦
// dp[t][j] = max(dp[1-t][j-1], dp[1-t][j], dp[1-t][j+1]) + a[i][j];
int N, m, x, T, begin, end;
while (scanf("%d", &N) != EOF && N) {
memset(a, 0, sizeof(a));
memset(dp, 0, sizeof(dp));
m = 0;
while (N--) {
scanf("%d%d", &x, &T);
++a[T][x];
m = max(m, T);
}
int t = 1;
for (int i = 1; i <= m; ++i) {
begin = max(5-i, 0);
end = min(5+i, 10);
// 如果i = 1 的話,也就是說第1秒鐘,j的位置只能是[4, 6];
// 如果i = 2 的話, 也就是說第2秒鐘,j的位置只能是[3, 7];
// 如果i = 3 的話, 也就是說第3秒鐘,j的位置只能是[2, 8];
// 如果i = 4 的話, 也就是說第4秒鐘,j的位置只能是[1, 9];
// 如果i >= 5 的話, 也就是說第5秒鐘及以後,j的位置可以是[0, 10];
//沒有到達的i, j默認都爲0,比如dp[1][3]也就是第1秒鐘在位置3獲得的餡餅,顯然,第一秒鐘
//不可能從5跑到3,所以dp[1][3] = 0
for (int j = begin; j <= end; ++j) {
dp[t][j] = max(max(dp[1-t][max(0, j-1)], dp[1-t][j]),
dp[1-t][min(10, j+1)] ) + a[i][j];
}
t = 1 - t;
}
int MAX = -1;
for (int j = 0; j <= 10; ++j)
MAX = max(MAX, dp[m%2][j]);
cout << MAX << endl;
}
return 0;
}
注:鄙人最近按照此分類來刷題,假期的最低限度是刷掉所有的DP類,並且每一道題目寫一個解題報告,如果有志同道合的朋友,歡迎加QQ 823797837共同學習交流,也可以加羣ACM新手羣161986576,老鳥飛過