POJ 3666 Making the Grade

这个题要往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));
}

 

 


 

  • 3
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值