您的位置:首页 > 其它

POJ 3666 Making the Grade

2012-02-04 15:09 260 查看
这个题要往DP上想(左偏树什么的也不会)

首先要知道这样一个结论:一定存在一个最优解,使得整理后的数组中不存在整理前数组中不存在的数,亦即:对于每个Bi,一定存在j,使得Bi=Aj。

可以这么想,在做调整时,一定是这么做的,先选出连续的三个数abc,

假设a<=c,那么要组成递增序列,

如果b>=a && b<=c,则不需调整;

如果b<a,则最小的调整可以是把b变成a;

如果b>c,则最小的调整可以是把b变成c.

所以归纳可知上面结论成立。

dp[i][j] 表示考虑前i个元素,最后元素为序列中 第j小元素的最优解,a[]数组存原始数组,b[]是对a从小到大排序。

dp[i][j] = MIN(dp[i-1][k]) + abs(a[i]-b[j]), (0<k<=j)

这样总时间复杂度是n^3,空间复杂度是n^2.

可以把状态转移时间优化到o(1),滚动数组把空间优化到o(n).

具体可以参考代码
#include<cstdio>
#include<stdlib.h>
#include<cstring>
#include<algorithm>
#include<math.h>
using namespace std;
int n,ans;
int a[2010],b[2010],dps[2010],m[2010];
int Min(int a,int b){
	return a>b?b:a;
}
void dp(){
	int i,j;
	memset(m,0,sizeof(m));
	for(i=1;i<=n;i++)
		for(j=1;j<=n;j++){
			dps[j]=m[j]+abs(a[i]-b[j]);
			if(j>1)
				m[j]=Min(dps[j],m[j-1]);
			else
				m[j]=dps[j];
		}
	ans=dps[1];
	for(i=1;i<=n;i++)
		ans=Min(ans,dps[i]);
}
int main(){
	int i,j;
	scanf("%d",&n);
	for(i=1;i<=n;i++){
		scanf("%d",&a[i]);
		b[i]=a[i];
	}
	sort(b+1,b+n+1);
	
	dp();
	int ans1=ans;
	for(i=1;i<=n/2;i++){
		int tem=b[i];
		b[i]=b[n-i+1];
		b[n-i+1]=tem;
	}
	dp();
	int ans2=ans;
	printf("%d\n",Min(ans1,ans2));
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: