POJ 3666 DP+滚动数组的优化+滚动数组的优化

Making the Grade

A straight dirt road connects two fields on FJ's farm, but it changes elevation more than FJ would like. His cows do not mind climbing up or down a single slope, but they are not fond of an alternating succession of hills and valleys. FJ would like to add and remove dirt from the road so that it becomes one monotonic slope (either sloping up or down).

You are given N integers A1, ... , AN (1 ≤ N ≤ 2,000) describing the elevation (0 ≤ Ai ≤ 1,000,000,000) at each of N equally-spaced positions along the road, starting at the first field and ending at the other. FJ would like to adjust these elevations to a new sequence B1, . ... , BN that is either nonincreasing or nondecreasing. Since it costs the same amount of money to add or remove dirt at any position along the road, the total cost of modifying the road is

A 1 -  B 1| + |  A 2 -  B 2| + ... + |  AN -  BN |

Please compute the minimum cost of grading his road so it becomes a continuous slope. FJ happily informs you that signed 32-bit integers can certainly be used to compute the answer.

Input

* Line 1: A single integer: N
* Lines 2..N+1: Line i+1 contains a single integer elevation: Ai

Output

* Line 1: A single integer that is the minimum cost for FJ to grade his dirt road so it becomes nonincreasing or nondecreasing in elevation.

Sample Input

7
1
3
2
4
5
3
9

Sample Output

3

题目大意:给你一个序列,要求在当前序列的基础上将其改成非严格的递增或者递减序列,求需要修改的最小绝对值的和

最小化--DP

怎么推出最小化的dp转移方程

最后的序列一定是原序列中的某几个数进行加减操作所得到的,因此可以先对其进行排列一下,然后就可以得到任意两个数的差的绝对值,然后枚举状态,看这些数中以哪一个数结尾的序列差的绝对值的和最小。

dp[i][j]表示前i个数中以b[j](原数组从小到大排序后的数组)结尾的最优答案

dp[i][j]=min(dp[i-1][k])+abs(b[j]-a[i]) k={1,...j}什么意思呢,就是你要看第i个元素改动的最小值,你需要从前i-1个元素里面找一个最小的变动量,不能超过i,这也就是代码里面内层for循环里面的那一句

有点乱,上面的k为什么只能到j,而不是从1到n中我选择最小的一个加到dp[i][j]里面,因为dp[i][j]的意思是前i个数中以b[j]结尾的最小改变量的和,你不能去找j开外的数来推j以内的最小值,对吧?

#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstring>
using namespace std;
#define rep(i,a,b) for(int i=a;i<=b;i++)
#define  init(a,b) memset(a,b,sizeof a)
#define Abs(a)  ((a)>0?a:-(a))
const int N=1e6+5;
const int MOD=1000000007;
typedef long long ll;
ll dp[2020][2020];
ll a[2010];
ll b[2020];
int main()
{
//    freopen("in.txt", "r", stdin);
//    freopen("out.txt", "w", stdout);
    int n;
    scanf("%d",&n);
    rep(i,1,n)
    scanf("%lld",&a[i]),b[i]=a[i];
    sort(b+1,b+1+n);
    init(dp,0);
    rep(i,1,n)
    {
        ll minn=MOD;
        rep(j,1,n){
            minn=min(minn,dp[i-1][j]);
        dp[i][j]=Abs(b[j]-a[i])+minn;
        }
    }
    printf("%lld\n",*min_element(dp[n]+1,dp[n]+1+n));
    return 0;
}

因为这一道题目是只有两种状态的相互转化,前i个元素是由前i-1个元素推出得来的,那就可以用滚动数组降低空间复杂度

#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstring>
using namespace std;
#define rep(i,a,b) for(int i=a;i<=b;i++)
#define  init(a,b) memset(a,b,sizeof a)
#define Abs(a)  ((a)>0?a:-(a))
const int N=1e6+5;
const int MOD=1000000007;
typedef long long ll;
ll dp[3][2020];
ll a[2010];
ll b[2020];
int main()
{
//    freopen("in.txt", "r", stdin);
//    freopen("out.txt", "w", stdout);
    int n;
    scanf("%d",&n);
    rep(i,1,n)
    scanf("%lld",&a[i]),b[i]=a[i];
    sort(b+1,b+1+n);
    init(dp,0);
    rep(i,1,n)
    {
        ll minn=MOD;

        rep(j,1,n){
            minn=min(minn,dp[(i-1)%2][j]);
        dp[i%2][j]=Abs(b[j]-a[i])+minn;
        }
    }
    printf("%lld\n",*min_element(dp[n%2]+1,dp[n%2]+1+n));
    return 0;
}

猜你喜欢

转载自blog.csdn.net/c___c18/article/details/82758395