链家2018链习生招聘 编程题三

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

posted on 2017-09-03 17:07  Beserious  阅读(1225)  评论(7编辑  收藏  举报