1. 程式人生 > >[USACO10DEC] Treasure Chest

[USACO10DEC] Treasure Chest

題目連結

90 Points:智障的區間 DP……設 dp[i][j] 表示區間 [i, j] 能取的最大價值,但我還是 sd 地開了第三維表示先取還是後取的價值。

交上去以為能 A,結果 #2 開心地 MLE……一看記憶體,64MB(把評測機吊起來打一頓)……

100 Points:有些神仙……區間 DP 的滾動陣列,dp[i] 表示以 i 為首的區間得到的最大價值。

換一種思路,定義 dp[l][r] 為在區間 [l,r] 先手的人能取到的最大值,區間的長度每加 1,先手就會互換一次,為了讓這一次的先手更大,就要讓上一次更小,於是得到:

$ dp[l][r] = sum[r] - sum[l - 1] - min(dp[l][r - 1], dp[l + 1][r]); $

斜著滾掉一維……dp[i] 為從 i 到 i + l - 2 區間最優解:

$ dp[i] = sum[j] - sum[i - 1] - min(dp[i], dp[i + 1]); $

放上程式碼。

90 分:

#include <queue>
#include <cstdio>
#include <cctype>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;

const int maxn = 5000 + 10;
int n, c[maxn], dp[maxn][maxn][2];

int main(int argc, const char *argv[])
{
  freopen("..\\nanjolno.in", "r", stdin);
  freopen("..\\nanjolno.out", "w", stdout);

  scanf("%d", &n);
  for(int i = 1; i <= n; ++i) scanf("%d", &c[i]), dp[i][i][0] = c[i];
  for(int i = 1; i < n; ++i)
    dp[i][i + 1][0] = max(c[i], c[i + 1]), dp[i][i + 1][1] = min(c[i], c[i + 1]);
  for(int i = 3; i <= n; ++i) {
    for(int l = 1; l <= n - i + 1; ++l) {
      int r = l + i - 1;
      if( c[l] + dp[l + 1][r][1] > c[r] + dp[l][r - 1][1] )
        dp[l][r][0] = c[l] + dp[l + 1][r][1], dp[l][r][1] = dp[l + 1][r][0];
      else dp[l][r][0] = c[r] + dp[l][r - 1][1], dp[l][r][1] = dp[l][r - 1][0];
    }
  }
  printf("%d %d\n", dp[1][n][0], dp[1][n][1]);

  fclose(stdin), fclose(stdout);
  return 0;
}

100 分:

#include <queue>
#include <cstdio>
#include <cctype>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;

const int maxn = 5000 + 10;
int n, c[maxn], dp[maxn];

int main(int argc, const char *argv[])
{
  freopen("..\\nanjolno.in", "r", stdin);
  freopen("..\\nanjolno.out", "w", stdout);

  scanf("%d", &n);
  for(int i = 1; i <= n; ++i) scanf("%d", &dp[i]), c[i] = c[i - 1] + dp[i];
  for(int i = 2; i <= n; ++i) {
    for(int l = 1; l <= n - i + 1; ++l) {
      int r = l + i - 1;
      dp[l] = c[r] - c[l - 1] - min(dp[l], dp[l + 1]);
    }
  }
  printf("%d\n", dp[1]);

  fclose(stdin), fclose(stdout);
  return 0;
}