POJ3186.Treats for the Cows(区间DP)

题目链接: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;
}

猜你喜欢

转载自blog.csdn.net/littlegoldgold/article/details/107240499