标签:poj3666 usaco 2008 feb gold 动规 cow game
题意:有若干个数,然后可以花费i的代价让某个数+i或者-i。
现在要求让你把序列排成不升或者不降,问最小代价。
题解:
首先可以证明,最优花费下最后所有的数都可以是现在的某个数:
证:如果两个数调整后在两个数中间,那么可以把两个数都变为其中一个数,而代价显然是等同的。
这个出来后就好做了。
我们可以先离散化一下,然后f[i][j]表示第i个数变为j时1~i这些数保持非严格单调的最小花费
转移时f[i][j]不必n*n枚举,可以维护一个前缀最优(非常水),然后O(1)转移。
然后做一遍非升,一遍非降出解。
代码:
#include <cmath> #include <cstdio> #include <cstring> #include <iostream> #include <algorithm> #define N 2500 #define inf 0x3f3f3f3f3f3f3f3fll using namespace std; struct LSH { int x,id; bool operator < (const LSH &a)const{return x<a.x;} }lsh[N]; int cnt,n,w[N]; long long f[N][N]; int main() { // freopen("test.in","r",stdin); int i,j,k; scanf("%d",&n); for(i=1;i<=n;i++)scanf("%d",&lsh[i].x),lsh[i].id=i; sort(lsh+1,lsh+n+1),lsh[0].x=-1; for(i=1;i<=n;i++) { if(lsh[i].x!=lsh[i-1].x)lsh[++cnt].x=lsh[i].x; w[lsh[i].id]=cnt; } // 离散化结束,lsh中对应原值 //升序 for(i=1;i<=n;i++) { long long temp=inf; for(j=0;j<=cnt;j++) { temp=min(temp,f[i-1][j]); f[i][j]=temp+abs(lsh[w[i]].x-lsh[j].x); } } long long ans1=inf; for(i=0;i<=cnt;i++)ans1=min(ans1,f[n][i]); //降序 for(i=1;i<=n;i++) { long long temp=inf; for(j=cnt;j>=0;j--) { temp=min(temp,f[i-1][j]); f[i][j]=temp+abs(lsh[w[i]].x-lsh[j].x); } } long long ans2=inf; for(i=0;i<=cnt;i++)ans2=min(ans2,f[n][i]); cout<<min(ans1,ans2)<<endl; return 0; }
【POJ3666】【USACO 2008 Feb Gold】 2.Cow Game 动规
标签:poj3666 usaco 2008 feb gold 动规 cow game
原文地址:http://blog.csdn.net/vmurder/article/details/42275119