动规-POJ-3666

http://poj.org/problem?id=3666

Making the Grade

给定一个正整数数列,要求通过对每一个元素加上或减去任意值,使得数列非严格递增(虽然题设要求还可以非严格递减,但是实际数据只要求非严格递增)。

求所得数列与原数列各个对应元素差的绝对值之和的最小值。

解题报告

思路

由于要求最终改变的绝对值和最小,所以可以知道所得解的数列中元素的最大值即原数列arr的最大值。

以此类推,所得解的数列中,每个元素必然取自原数列arr。

那么可将原数列进行排序,得到可取值数列num。

若依次对数列的每个元素进行修改,那么修改第i个数的值后的总代价仅仅与修改至第i-1个数的总代价有关。

而修改可取的值均来自num,则有状态转移方程:

修改arr[i]为num[j]后的总代价为:dp[i][j] = abs(arr[i] - num[j]) + min( dp[i-1][0], d[[i-1][1], ... , dp[i-1][j] )

代码

#include <iostream>
#include <cstring>
#include <algorithm>

using namespace std;

const int maxn = 2003;

int a[maxn], b[maxn];
int num[maxn];
int dp[maxn][maxn];
int n;

int Work(int *arr){
    int last = arr[0];
    int minNum;
    for(int i=1; i<=n; i++){
        dp[0][i] = 0;
    }
    for(int i=1; i<=n; i++){
        minNum = dp[i-1][1];
        for(int j = 1; j<=n ; j ++){
            minNum = min(dp[i-1][j], minNum);
            dp[i][j] = abs(arr[i] - num[j]) + minNum;
        }
    }
    int ans = dp[n][1];
    for(int i=1; i<=n; i++){
        ans = min(dp[n][i], ans);
    }
    return ans;
}

int main(){

    while(cin >> n){
        for(int i=1; i<=n; i++){
            cin >> a[i];
            num[i] = a[i];
            b[n-1-i] = a[i];
        }
        sort(num+1, num+n+1);
        cout << Work(a)<< endl;
    }
    return 0;
}

--(完)--

 

posted @ 2017-06-12 09:40  Bcai  阅读(223)  评论(0编辑  收藏  举报