路面修整

路面修整 

【问题描述】

   

     大老板Mr. Yao打算好好修一下公司门口的那条凹凸不平的路。按照Mr. Yao的设想,修好后的路面高度应当单调上升或单调下降,也就是说,高度上升与高度下降的路段不能同时出现在修好的路中。

    整条路被分成了N段,N个整数A_1, ... , A_N (1 <= N <= 2,000)依次描述了每一段路的高度(0 <= A_i <= 1,000,000,000)。Mr. Yao希望找到一个恰好含N个元素的不上升或不下降序列B_1, ... , B_N,作为修过的路中每个路段的高度。由于将每一段路垫高或挖低一个单位的花费相同,修路的总支出可以表示为:

         |A_1 - B_1| + |A_2 - B_2| + ... + |A_N - B_N|

    请你计算一下,Mr. Yao在这项工程上的最小支出是多少。Mr. Yao向你保证,这个支出不会超过2^31-1。

动态规划:

分析一下需要知道的量:路面的位置,路面需要调整的高度,

所以我们设f[i,j]表示到了路面为i的位置,高度为j,但它怎么由前面的转移过来呢,f[i,j]:=min(f[i,k])+abs(a[i]-j)

它的状态有前方的状态转移过来:它i位置的高度为k,(K<=j),的最小代价,再加上将i位置调整到j高度的花费。

K究竟是多少呢?有贪心的思想可知,调整时调整到原来某个高度一定最好(调整到与某个路面相同的高度,保证了不降或不升,但若调整到其他高度,那么代价一定又加上了比相同高度的多余代价),开一个b[i]数组,记录a[i]的高度,排序,f[i,j]:=min(f[i,k])+abs(a[i]-b[j])中的j含义变成了第j种高度,for i:=1 to n do (阶段)

        For j:=1 to n do (状态)

          For k:=1 to j do (决策)

N^3的时间复杂度过不了,所以改变方程的含义f[i,j]:=min(f[i,j-1],f[i-1,j]+abs(a[i]-b[j]))此时f[i,j]表示到了路面为i的位置,高度小于或等于j,且符合题意。它由前方两种状态转移过来:1.第i-1种为j,则它的代价需要加上abs(a[i-b[j]]);2.f[i,j-1]表示j从1到n转移时记录的将第i段路高度设为小于或等于b[j-1]时最小值,每一次用当前状态表示最小,这样将时间复杂度降到了n^2;最后,由于不知道序列是不降或不升,所以将b[i]数组倒过来再做一遍不降的情况。俩次取min。

代码实现:

program exam;

var

  a,tmp,c:array[0..2000] of longint;

  n,ans,i:longint;

  g,f:array[0..2000,0..2000] of longint;

function min(a,b:longint):longint;

begin

  if a>b then

    exit(b)

  else

    exit(a);

end;

procedure swap(var a,b:longint);

var

  t:longint;

begin

  t:=a;

  a:=b;

  b:=t;

end; 

procedure qsort(l,r:longint);

var

  i,j,x:longint;

begin

  i:=l;

  j:=r;

  x:=a[(l+r) div 2];

  repeat

    while x>a[i] then

      inc(i);

    while x<a[j] then

      dec(j);

    if i<=j then

    begin

      swap(a[i],a[j]);

      inc(i);

      dec(j);

    end;

  until i>j;

  if i<r then

    qsort(i,r);

  if l<j then

    qsort(l,j);

end;

procedure dp;

var

  i,j::longint;

begin

  for i:=1 to n do

    g[i,0]:=maxlongint;                // 初始化

  for i:=1 to n do

    for j:=1 to n do              //dp[i,j]:=min(dp[i-1,j]+abs(a[i]-c[j]),dp[i,j-1])

    begin

      f[i,j]:=g[i-1,j]+abs(a[i]-c[j]); // c 为排序后的数组

      g[i,j]:=min(f[i,j],g[i,j-1]);

    end; 

  ans:=min(ans,g[n,n]);

end;

begin

  ans:=maxlongint;

  readln(n);

  for i:=1 to n do

    readln(a[i]);

  tmp:=a;

  qsort(1,n);

  c:=a;

  a:=tmp;

  dp;

  writeln(ans);

end.

原文地址:https://www.cnblogs.com/fengxiudong/p/6017305.html