[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]));
}