[USACO13MAR]牛跑The Cow Run

[USACO13MAR]牛跑The Cow Run

區間Dp

題解:

藍書上有道修長城的題目和這個類似啊
好像那個每個點單位時間帶來的花費還不一樣

沒關係,都是一種做法

很明顯任意時刻解決掉的牛都是一段連續的區間
設f[i][j][0/1]表示已經解決了[i,j]的牛,當前站在i或j,的最小花費
轉移很簡單,詳見代碼
注意要從0出發,因此添加0的虛擬點,排序後的位置設爲s
邊界f[s][s][0/1]=0,其餘=INF
先枚舉區間長度,並且要求區間的左端點在s左邊,右端點在s右邊

Code:

#include <algorithm>
#include <iostream>
#include <cstring>
#include <cstdio>
#define D(x) cout<<#x<<" = "<<x<<"  "
#define E cout<<endl
using namespace std;
const int N = 1005;
const int INF = 0x3f3f3f3f;

int n,p[N],f[N][N][2];

inline int myabs(int x){ return x>=0 ? x : -x; }
inline void upd(int &a,int b){ a=min(a,b); }

int main(){
    freopen("a.in","r",stdin);
    scanf("%d",&n);
    bool bo=false;
    for(int i=1;i<=n;i++){
        scanf("%d",p+i);
        if(p[i]==0) bo=true;
    }
    if(!bo){ n++; p[n]=0; }
    sort(p+1,p+1+n); 
    int st=lower_bound(p+1,p+1+n,0)-p;
//  D(n); D(st); E;
//  for(int i=1;i<=n;i++) printf("%d ",p[i]); E;
    memset(f,0x3f,sizeof(f));
    f[st][st][0]=f[st][st][1]=0;
    for(int len=2;len<=n;len++){
        for(int i=1;i+len-1<=n;i++){
            int j=i+len-1; 
            if(i>st || j<st) continue;
            int cnt=n-len+1;
            upd(f[i][j][0],f[i+1][j][0]+cnt*(p[i+1]-p[i]));
            upd(f[i][j][0],f[i+1][j][1]+cnt*(p[j]-p[i]));
            upd(f[i][j][1],f[i][j-1][0]+cnt*(p[j]-p[i]));
            upd(f[i][j][1],f[i][j-1][1]+cnt*(p[j]-p[j-1]));
//          D(i); D(j); D(f[i][j][0]); D(f[i][j][1]); E;
        }
    }
    printf("%d\n",min(f[1][n][0],f[1][n][1]));
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章