小明有n(1<=n<=2000)個美味的食物,他想賣掉他們來賺錢,這些書屋放在一些箱子里,它們有些有趣的特性:
(1)這些食物被編號1~n,每一天小明都可以從這排箱子的頭部或者尾部取出食物去買
(2)這些食物放得越久,年齡越大,價值越大,食物i有一個廚師的價值V(i)
(3)放了a天后,年齡為a,食物最終的價值為V(i)xa
給定每一個食物的初始價值V(i),求出小明賣掉他們后能獲得的最大價值,第一天出售的食物的年齡為1此后,每增加一天食物的年齡就增加1
提示
樣例說明:小明出售這些食物(初始值為1,3,1,5,2)的順序為:第一天賣掉第一個,第二天賣掉第5個,第三天賣掉第2個,第四天賣掉第3個,第五天賣掉第4個。獲得的最大價值 1x1 + 2x2 + 3x3 + 4x1 + 5x5 = 43
輸入
第一行,一個整數n
第i+1行:每行為食物i的初始價值V(i)
···
輸入樣例
5
1
3
1
5
2
輸出樣例
43
···
思路:
看樣子dfs一下就可以,但是數據量2000,必然不能暴力 ,由於這道題目要求賣掉最后一個或者最前一個食物,不同的取法會得到不同的區間,最后直到剩下一個食物[i,i]。
可以考慮區間dp 。那么最優子結構是什么呢?
最優子結構不就是區間上的最大值嗎,下一個狀態 = 當前的狀態左+v[i] 或 右+v[j]轉移得到,所以得到
dp[i][j] = max(dp[i][j-1]+v[j],dp[i+1][j]+v[i]) 這里的v是年數*初始值
但是這種dp的時間復雜度是O(n^3),由於本題目的特殊性,即長度為x的區間只能由長度為x-1的區間和長度為1的區間合並得到。所以這里的dp可以寫成
dp[p][i] = max(dp[p-1][i] + v[i+p-1]*(n-p+1), dp[p-1][i+1]+v[i]*(n-p+1));
代碼如下
#include <bits\stdc++.h>
using namespace std;
int dp[2010][2010];
int main() {
int n;
while (cin >> n) {
vector<int> v(n);
memset(dp, 0, sizeof dp);
for (int i = 0; i < n; ++i) cin >> v[i];
// dp[p][i] 以i開始 長度為p能得到的最大值
for (int p = 1; p <= n; ++p) {
for (int i = 0; i <= n - p; ++i) {
dp[p][i] = max(dp[p-1][i] + v[i+p-1]*(n-p+1), dp[p-1][i+1]+v[i]*(n-p+1));
}
}
cout << dp[n][0] << endl;
}
return 0;
}