1. 程式人生 > >URAL 2072. Kirill the Gardener 3(dp)

URAL 2072. Kirill the Gardener 3(dp)

Description

Kirill the gardener has got a new task. He has to water the flowers growing on the huge flowerbed! It should be mentioned that the bed is very long and narrow at the same time. So from bird’s-eye view (and Kirill growth too) it looks like a straight line, where n points-flowers are located at regular intervals. For this job Kirill has a watering pot of infinite volume and smartwatch that shows moisture content of each flower before watering. The watering takes too much time, so the most dried flowers can die, which is unacceptable. So Kirill decided to water the flowers in order of their non-decreasing dryness. On the other hand, he wants to finish the watering as soon as possible, because there are a lot of other interesting things.
Assume that watering of one flower and walking between two neighbor flowers takes Kirill one minute. Can you figure out the time in which the young gardener will complete his job if he acts optimally? Initially Kirill stands near the leftmost flower.

Input

The first line contains an integer n (1 ≤ n ≤ 10 5) — it’s amount of flowers in the flowerbed. The second line contains n integers separated by spaces — it‘s moisture content of flowers given in order of their positions in the flowerbed from left to right. Moisture content is an integer from 1 up to 10 9 (including both).

Output

In the only line print an integer — the minimal time in which Kirill would complete watering.

Example

input
6
3 2 5 6 2 5
output
21
input
6
4 1 3 2 2 3
output
16

題目描述

有n朵花,每個花有一個權值,權值越小越優先澆水,澆水和移動一個位置都需要一個單位時間,初始位置在第一個位置,問把所有的花澆一遍需要的最小的時間是多少.

解題思路

先將花按照權值進行排序,規定相同權值的花為一個區間,貪心策略如果要使結果最小,一定是從區間的最左邊或者最右邊和其他的區間的最左邊或者最右邊進行相連.
於是則有dp思想:
dp[i][0]表示第 i 個區間的澆水方向是從最右側到最左側;
dp[i][1]表示第 i 個區間的澆水方向是從最左側到最右側.
prel,prer 標記上一個區間的左端點和右端點.
則dp[i][0]=min(從第 i-1區間的左端點(dp[i-1][0]) -> 第 i 區間的右端點,從第 i-1 區間的右端點(dp[i-1][1]) ->第 i 區間的右端點)
=min(dp[i-1][0]+abs(prel-a[j].id),dp[i-1][1]+abs(prer-a[j].id)),
同理,dp[i][1]=min(dp[i-1][1]+abs(prer-a[i].id),dp[i-1][0]+abs(prel-a[i].id)),

這裡寫圖片描述
如圖為樣例2 dp[i][0].

程式碼實現

#include<bits/stdc++.h>
#define IO ios::sync_with_stdio(false);\
    cin.tie(0);\
    cout.tie(0);
using namespace std;
typedef long long ll;
#define INF 0x3f3f3f3f
const int maxn = 1e5+10;
ll dp[maxn][2];
//dp[i][0] 代表第 i 個區間先到右端點,再由右端點走至左端點
//dp[i][1] 代表第 i 個區間先到左端點,再由左端點走至右端點
struct node
{
    ll val;
    ll id;
}a[maxn];
bool cmp(node x,node y)
{
    if(x.val==y.val)
        return x.id<y.id;
    else return x.val<y.val;
}
int main()
{
    IO;
    ll n;
    cin>>n;
    memset(dp,INF,sizeof(dp));
    dp[0][1]=0,dp[0][0]=0;
    for(int i=1;i<=n;i++)
    {
        cin>>a[i].val;
        a[i].id=i;
    }
    sort(a+1,a+n+1,cmp);
    ll sec=1;
    ll prel=0,prer=0;
    ll res=0;
    for(int i=1;i<=n;i++)
    {
        int j=i+1;
        while(a[i].val==a[j].val&&j<=n) j++;
        --j;
        res+=abs(a[j].id-a[i].id);
        dp[sec][0]=min(dp[sec-1][0]+abs(prel-a[j].id),dp[sec-1][1]+abs(prer-a[j].id));
        dp[sec][1]=min(dp[sec-1][1]+abs(a[i].id-prer),dp[sec-1][0]+abs(a[i].id-prel));
        ++sec;
        prel=a[i].id,prer=a[j].id;
        i=j;
    }
    cout<<min(dp[sec-1][1],dp[sec-1][0])+res+n-1<<endl;
    return 0;
}