SJTU OJ 1282 修路 題解

1282. 修路

Description

蹦蹦跳跳結束後,cxt回頭看看本身走過的路坑坑窪窪的,心中很是不爽,他表示要把這段路的路面高度修成單調上升的或者單調降低的,整條路能夠當作 N段,N個整數A1,…..,An(1<=n<=2000)依次描述了每一段路的高度(0<=Ai<=1000000000)。 但願找到一個剛好含N個元素的不上升或不降低的序列B1,……,Bn,做爲修過的路中每一個路段的高度。ios

因爲將每一段路墊高或挖低一個單位消耗的體力相同,因而能夠表示爲:spa

|A1-B1|+|A2-B2|+…..+|An-Bn|code

請你計算一下,要修好這段道路,最少消耗多少體力。消耗的整體力不會超過2^31-1orm

Input Format

輸入文件的第一行僅有一正整數N,如下的N行每行一個整數Ai,表示路面的高度。排序

Output Format

輸出文件僅有一個正整數,表示若是把路修成高度不上升或不降低的最小花費ip

Sample Input

7
1
3
2
4
5
3
9

Sample Output

3

Hint

將第一個高度爲3的路段的高度減小爲2,將第二個高度爲3的路段的高度增長到5,總花費爲|2-3|+|5-3|=3,而且各路段的高度爲一個不降低序列 1,2,2,4,5,5,9。ci


================================it

題解正文io

================================class

  1. 題目分析

    1. 這是一道動態規劃題目,求最小花費使道路變成不嚴格單調遞增或不嚴格單調遞減,數據大小用int便可。

    2. 修改後的值確定是原來數列裏的值。‘
    3. 對於結果來講,每一段都是不嚴格單調遞增或不嚴格單調遞減的數列。
  2. 解決方法
    1. 咱們須要把一個數列排序(上升或降低均可以),來做爲計算時的參考標準。(爲何須要這個標準呢?由於上面提到修改後的值確定是原來粗線過的,而最終的結果是不嚴格單調的,因此與排序後的數列比較就很方便)
    2. 咱們須要對輸入的數列進行排序但不但願影響後來的操做,因此顯然咱們得把原數列複製一遍再排序。
    3. 樸素的思想就是咱們依次把排序後的數列的某個數看成是咱們最終修正後的路面的結束值(即最大或最小),由於看成參考的數列是排序過的,因此能保證結果知足題意,即不嚴格單調。
    4. 用f[i][j] 表示將原數列的前i個元素改成不嚴格單調且第i個元素改成排序後數列的第j個元素時所花費的最小的體力。用a表示原數列,b表示排序後的數列。獲得狀態轉移方程f[i][j]=min{f[i-1][k]+abs(b[j]-a[i])}(1<=k<=j)
    5. 最後的結果就是從f[i][j]中找到最小值。
  3.     #include<iostream>
        #include<cmath>
        #include<algorithm>
        using namespace std;
         
        int n,ans=1<<30,a[2005],c[2005],f[2005][2005],g[2005][2005];
         
        void init()
        {
            cin>>n;
            for(int i = 1; i <= n ; ++i)
            {
                cin >> a[i];
                c[i]=a[i];
            }
            sort(c+1,c+n+1);
        }
        void sol()
        {
            for(int i = 1; i <= n; ++i)
            {
                for(int j = 1; j <= n; ++j)
                {
                    f[i][j] = g[i-1][j] + abs(a[i]-c[j]);
                    if(j == 1) g[i][j] = f[i][j];
                    else g[i][j] = min(f[i][j],g[i][j-1]);
                }
            }
            for(int i = 1; i <= n; ++i)
            ans = min(ans ,f[n][i]);
        }
         
        int main()
        {
            init();
            sol();//算一遍遞增
            for(int i = 1; i <= n/2 ; ++i)
                swap(c[i],c[n-i+1]);
            sol();//算一遍遞減
            cout<<ans;
        }
相關文章
相關標籤/搜索