1. 程式人生 > 實用技巧 >Grazing on the Run 題解

Grazing on the Run 題解

【題目大意】

大致題意就是,你的初始座標為\(x\),你要去數軸上的\(n\)個點,問你到達所有點的時間總和最小是多少。

直接貪心肯定不行,所以考慮\(DP\)

先把座標離散(也就是預處理兩點距離\(dis[i][j]=abs(a[i]−a[j])\)

接下來考慮如何dp。

關注到一個性質,如果到目前為止,奶牛吃過最左的草堆編號為\(l\),吃過最右的草堆編號為\(r\),則如果奶牛不是傻它肯定把\([l,r]\)的草堆都吃過了,因為它吃草速度是瞬時的,都經過了肯定要嫖一口。

那很明顯應該是個區間dp了。

不難定義出狀態\(f[0/1][i][j]\)表示已經吃完\([i,j]\)的草了,且現在在左端\(i(0)\)

,在右端\(j(1)\),所需的最少時間和。

轉移根據意義模擬一下就好了,假如我現在從區間的某端\(k\)轉移到某點\(l\),則花去時間為\(dis[k][l]\),在這個時間內除了區間\([i,j]\),其他所有草堆的腐敗值都增加了\(1\)

具體轉移順序可以打個記搜。也可以直接迴圈轉移——列舉區間長度,再列舉左端點。然後對於這道題內部再分類討論一下處於左右端位置即可。時間複雜度為\(O(N^2)\)

#include <bits/stdc++.h>
using namespace std ;
const int N = 1005 , INF = 0x3f3f3f3f ;
int n , s , st ;
int p[ N ] ;
int f[ N ][ N ][ 2 ] ;
int dis[ N ][ N ] ;
signed main () {
    scanf ( "%d%d" , &n , &s ) ;
    for ( int i = 1 ; i <= n ; i ++ ) scanf ( "%d" , &p[ i ] ) ;
    p[ ++ n ] = s ;
    sort ( p + 1 , p + 1 + n ) ;
    for ( int i = 1 ; i <= n ; i ++ )
        for ( int j = 1 ; j <= n ; j ++ )
            dis[ i ][ j ] = dis[ j ][ i ] = abs ( p[ i ] - p[ j ] ) ;
    st = lower_bound ( p + 1 , p + 1 + n , s ) - p ;
    memset ( f , 0x3f , sizeof ( f ) ) ;
    f[ st ][ st ][ 0 ] = f[ st ][ st ][ 1 ] = 0 ;
    for ( int i = 1 ; i <= n ; i ++ ) {
        for ( int l = 1 ; l + i - 1 <= n ; l ++ ) {
            int r = i + l - 1 ;
            if ( f[ l ][ r ][ 0 ] < INF ) {
                if ( l > 1 ) f[ l - 1 ][ r ][ 0 ] = min ( f[ l - 1 ][ r ][ 0 ] , f[ l ][ r ][ 0 ] + dis[ l ][ l - 1 ] * ( n - i ) ) ;
                if ( r < n ) f[ l ][ r + 1 ][ 1 ] = min ( f[ l ][ r + 1 ][ 1 ] , f[ l ][ r ][ 0 ] + dis[ l ][ r + 1 ] * ( n - i ) ) ;
            }
            if ( f[ l ][ r ][ 1 ] < INF ) {
                if ( r < n ) f[ l ][ r + 1 ][ 1 ] = min ( f[ l ][ r + 1 ][ 1 ] , f[ l ][ r ][ 1 ] + dis[ r ][ r + 1 ] * ( n - i ) ) ;
                if ( l > 1 ) f[ l - 1 ][ r ][ 0 ] = min ( f[ l - 1 ][ r ][ 0 ] , f[ l ][ r ][ 1 ] + dis[ r ][ l - 1 ] * ( n - i ) ) ;
            }
        }
    }
    printf ( "%d\n" , min ( f[ 1 ][ n ][ 0 ] , f[ 1 ][ n ][ 1 ] ) ) ;
    return 0 ;
}