zoukankan      html  css  js  c++  java
  • poj3666 线性dp

    要把一个序列变成一个不严格的单调序列,求最小费用

    /*
    首先可以证明最优解序列中的所有值都能在原序列中找到 
    以不严格单增序列为例, 
    a序列为原序列,b序列为升序排序后的序列 
    dp[i][j]表示处理到a中第i个数,这些数中最大值为b[j]的费用,由单调性可知第i个数肯定变为b[j]
    那么dp[i][j]等价于第i个数变成b[j]的费用 
    那么有 dp[i][j]=abs(b[j]-a[i])+min(dp[i-1][k]),k<=j 
    */
    #include<iostream>
    #include<cstring>
    #include<cstdio>
    #include<algorithm> 
    using namespace std;
    #define maxn 2005
    #define ll long long 
    ll n,a[maxn],b[maxn],dp[maxn][maxn]; 
    
    ll solveup(){
        sort(b,b+n);
        memset(dp,0,sizeof dp);
        for(int i=0;i<n;i++)
            dp[0][i]=abs(a[0]-b[i]);//初始条件 
            
        for(int i=1;i<n;i++){
            ll Min=dp[i-1][0];
            for(int j=0;j<n;j++){
                Min=min(Min,dp[i-1][j]);//单调增加的集合可以直接用Min来维护 
                dp[i][j]=abs(a[i]-b[j])+Min; 
            }
        }    
        
        ll ans=dp[n-1][0];//求结果 
        for(int i=1;i<n;i++)
            ans=min(ans,dp[n-1][i]);
        return ans;     
    }
    
    int main(){
        while(scanf("%lld",&n)==1){
            for(int i=0;i<n;i++)scanf("%lld",&a[i]),b[i]=a[i];
            printf("%lld
    ",solveup());
        }
    }

    可以用滚动数组实现,空间省了许多

    /*
    滚动数组解法,第一维可以省去,dp[j]表示已经完成的序列用的最大值是b[j],状态i会覆盖状态i-1并且没有影响 
    dp[j]=abs(a[i]-b[j])+min(dp[k]),k<=j 
    */
    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    using namespace std;
    #define maxn 2005
    #define ll long long 
    
    ll n,a[maxn],b[maxn],dp[maxn];
    ll solve(){
        sort(b,b+n);
        for(int j=0;j<n;j++)
            dp[j]=abs(a[0]-b[j]);
        
        for(int i=1;i<n;i++){
            ll Min=dp[0];
            for(int j=0;j<n;j++){
                Min=min(Min,dp[j]);
                dp[j]=abs(a[i]-b[j])+Min;
            }
        }
        
        ll ans=dp[0];
        for(int j=1;j<n;j++) ans=min(ans,dp[j]);    
        return ans;
    } 
    
    int main(){
        while(scanf("%lld",&n)==1){
            for(int i=0;i<n;i++)scanf("%lld",&a[i]),b[i]=a[i];
            printf("%lld
    ",solve());
        }
    } 
  • 相关阅读:
    背水一战 Windows 10 (61)
    背水一战 Windows 10 (60)
    背水一战 Windows 10 (59)
    背水一战 Windows 10 (58)
    背水一战 Windows 10 (57)
    背水一战 Windows 10 (56)
    背水一战 Windows 10 (55)
    背水一战 Windows 10 (54)
    背水一战 Windows 10 (53)
    背水一战 Windows 10 (52)
  • 原文地址:https://www.cnblogs.com/zsben991126/p/10213890.html
Copyright © 2011-2022 走看看