方法来自poj 3666 经典dp-加载中...

感谢原作者。

题意

给一组正整数,让你对每个数进行增减使得最终形成一个不严格单调序列,并保证代价最小(每个数字增减绝对值的和)

方法

考虑不严格递增数列。

状态:f[i][j] 表示第i个数为第j小的最小代价,同时保证1到i不严格单增。

转移方程f[i][j]=min(f[i-1][1:j])+delta

此题可以用滚动数组。

注意:在获取f[i-1][1:j]时,不用加第三层循环。具体做法见代码。同时,因为这样不得使遍历顺序从小到大,滚动数组要开两条。

代码

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
using namespace std;
const int MAXN=2000+5;
int n;
long long int num[MAXN];
long long int nums[MAXN];
long long int f[2][MAXN];
long long int ans=(1<<30);
long long int aabs(long long int a){
    return a>0?a:-a;
}
void init(){
    memset(f,0,sizeof(f));
    cin>>n;
    for(int i=1;i<=n;i++){
        scanf("%lld",&num[i]);
        nums[i]=num[i];
    }
    sort(nums+1,nums+1+n);
}
int main(){
    init();
    for(int i=1;i<=n;i++)
        f[1][i]=aabs(num[1]-nums[i]);
    for(int i=2;i<=n;i++){
        long long int tmin=(1<<30);
        for(int j=1;j<=n;j++){
            tmin=min(tmin,f[(i+1)%2][j]);
            f[i%2][j]=tmin+aabs(num[i]-nums[j]);
        }
    }
    for(int i=1;i<=n;i++)
        ans=min(ans,f[n%2][i]);
    cout<<ans<<endl;
    return 0;
}
 posted on 2017-02-21 23:21  cylcy  阅读(124)  评论(0)    收藏  举报