题目链接:http://poj.org/problem?id=3186
题意:给出n个款待,每次从前端或者后端取一个款待,每个款待随着时间的进行会价值增长,第i个取出的价值为ivalue
解题思路:一开始打算直接用双端队列进行,每次进行开头和结尾的比较,取出小的那一个。但这样做存在问题是如果有多个前后端价值相同的情况会无法处理,比如 100 100 1101,如果从判断条件是 d.front()<=d.back()时取前端,这样取相比d.front()<d.back()取前端获得的值更大,所以存在漏洞。
正确做法是利用区间dp,逆序进行,从最后一个数取到第一个数,区间大小为1时为最后一个取出的数,依次选取两端较大的数,刚好可以模拟每次只能够从最前端或者最后端进行取值
dp转移方程为:
dp[i][i+k-1]=max(dp[i][i+k-2]+a[i+k-1](n-k+1),dp[i+1][i+k-1]+a[i]*(n-k+1));
#include<iostream>
#include<cstdio>
#include<deque>
using namespace std;
int n;
int ans;
deque<int> d;
int a[2100];
int dp[2100][2100];
int main(){
cin>>n;
for(int i=1;i<=n;i++){
scanf("%d",&a[i]);
dp[i][i]=a[i]*n;
}
for(int k=2;k<=n;k++){
for(int i=1;i+k-1<=n;i++){
dp[i][i+k-1]=max(dp[i][i+k-2]+a[i+k-1]*(n-k+1),dp[i+1][i+k-1]+a[i]*(n-k+1));
}
}
cout<<dp[1][n]<<endl;
/*for(int i=1;i<=n;i++){
int tmp;
scanf("%d",&tmp);
d.push_back(tmp);
}*/
//for(int i=1;i<=n;i++){
// if(d.front()<d.back()){
// ans+=d.front()*i;
// d.pop_front();
// }
// else{
// ans+=d.back()*i;
// d.pop_back();
// }
//}
//cout<<ans<<endl;
return 0;
}