1. 程式人生 > >Making the Grade (bzoj1592)

Making the Grade (bzoj1592)

二維 現在 ace nbsp 整數 n) pan mes 需要

題目描述

FJ打算好好修一下農場中某條凹凸不平的土路。按奶牛們的要求,修好後的路面高度應當單調上升或單調下降,也就是說,高度上升與高度下降的路段不能同時出現在修好的路中。 整條路被分成了N段,N個整數A_1, ... , A_N (1 <= N <= 2,000)依次描述了每一段路的高度(0 <= A_i <= 1,000,000,000)。FJ希望找到一個恰好含N個元素的不上升或不下降序列B_1, ... , B_N,作為修過的路中每個路段的高度。由於將每一段路墊高或挖低一個單位的花費相同,修路的總支出可以表示為: |A_1 - B_1| + |A_2 - B_2| + ... + |A_N - B_N| 請你計算一下,FJ在這項工程上的最小支出是多少。FJ向你保證,這個支出不會超過2^31-1。

輸入

第1行: 輸入1個整數:N * 第2..N+1行: 第i+1行為1個整數:A_i

輸出

第1行: 輸出1個正整數,表示FJ把路修成高度不上升或高度不下降的最小花費

樣例輸入

7
1
3
2
4
5
3
9

樣例輸出

3

提示

FJ將第一個高度為3的路段的高度減少為2,將第二個高度為3的路段的高度增加到5,總花費為|2-3|+|5-3| = 3,並且各路段的高度為一個不下降序列 1,2,2,4,5,5,9。

題解

考試的時候看到最小費用,想跑一跑網絡流試試。折騰了半天沒建出來圖,也想不到什麽數據結構。dp呢,狀態顯然需要二維來表示,第二維要開到5*10^8?不可想象。於是乎到最後連個暴力做法都沒想出來,直接不顧一切地從頭到尾補齊,因為數據過水居然水了40分= =。
正解是離散之後跑二維dp。在我的概念裏離散只能用於只和值的大小關系而不和值本身有關的題,沒想到還有這種用法。離散後的大小序號用於表示dp的第二維,這樣數組只用開到2000*2000,而求值則用第二維序號對應的準確值和原高度作差。雖然經過了離散化,原值並沒有被放棄,這樣的思路十分新奇。f[i][j]表示第i位高度為第j大需要的最小費用,
狀態轉移方程為f[i][j]=min{f[i-1][k]}+abs(g[j]-a[i]) 1<=k<=J(非下降),g[i]表示經過去重後第i大的原高度。這裏的min{f[i-1][k]}只要用一個變量來維護,初值為f[i-1][1],在轉移的過程中同時進行比較即可。非上升則只是從後向前轉移,min初始值為f[i+1][1]。

技術分享
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
using namespace std;
const  int sj=2010;
int n,h[sj],l[sj],temp,mi,f[sj][sj],jg;
struct W
{
     int hi,num,xu;
}w[sj];
int comp(const W&a,const W&b)
{
    return a.hi<b.hi;
}
void init() { scanf("%d",&n); for(int i=1;i<=n;i++) { scanf("%d",&h[i]); w[i].hi=h[i]; w[i].num=i; } sort(w+1,w+n+1,comp); w[1].xu=1; l[w[1].xu]=w[1].hi; temp=1; for(int i=2;i<=n;i++) { if(w[i].hi>w[i-1].hi) temp++; w[i].xu=temp; l[w[i].xu]=w[i].hi; } } int bj(int x,int y) { return x<y?x:y; } int main() { init(); for(int i=1;i<=n;i++) { mi=f[i-1][1]; for(int j=1;j<=temp;j++) { mi=bj(f[i-1][j],mi); f[i][j]=mi+abs(l[j]-h[i]); } } jg=0x7fffffff; for(int j=1;j<=temp;j++) jg=bj(f[n][j],jg); memset(f,0,sizeof(f)); for(int i=n;i>=1;i--) { mi=f[i+1][1]; for(int j=1;j<=temp;j++) { mi=bj(f[i+1][j],mi); f[i][j]=mi+abs(l[j]-h[i]); } } for(int j=1;j<=temp;j++) jg=bj(f[1][j],jg); printf("%d",jg); return 0; }
grading

Making the Grade (bzoj1592)