有 n 顆糖果排成一行,價值 v[1..n]。每天從兩端取一顆賣出,第 i 天賣出的糖果收益 = 價值 × i。求最大總收益。n ≤ 2000。
dp[i][j]:剩下區間 [i, j] 時,將這些糖果全部賣完能獲得的最大收益。注意:這是「從後往前」的視角,即當前已賣出 n - (j-i+1) 天,下一顆賣出是第 (n - (j-i+1) + 1) 天。
設當前區間長度 len = j-i+1,當前天數 day = n - len + 1。
dp[i][j] = max(
dp[i+1][j] + v[i] * day, // 取左端
dp[i][j-1] + v[j] * day // 取右端
)
初始條件:dp[i][i] = v[i] * n(最後一天賣最後一顆)。
按區間長度 len 從 2 到 n 遞增枚舉,保證轉移所需狀態已計算。
#include <cstdio>
#include <algorithm>
using namespace std;
const int MAXN = 2005;
int v[MAXN];
int dp[MAXN][MAXN];
int main() {
int n; scanf("%d", &n);
for (int i = 1; i <= n; i++) scanf("%d", &v[i]);
for (int i = 1; i <= n; i++) dp[i][i] = v[i] * n;
for (int len = 2; len <= n; len++) {
for (int i = 1; i + len - 1 <= n; i++) {
int j = i + len - 1;
int day = n - len + 1;
dp[i][j] = max(dp[i+1][j] + v[i] * day,
dp[i][j-1] + v[j] * day);
}
}
printf("%d\n", dp[1][n]);
return 0;
}
POJ 3186 展示了區間 DP 的核心思想:將「前向決策」轉化為「後向狀態」,通過區間長度枚舉實現無後效性轉移。掌握此模板可解決大類區間優化問題(如石子合併、戳氣球等)。