小明有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;
}