杭電1176解題報告

原題見這裏

關於解題的詳細步驟都已經在代碼註釋裏面了,這裏一定要注意,剛開始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,老鳥飛過

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章