[poj3666]Making the Grade
Description
A straight dirt road connects two fields on FJ‘s farm, but it changes elevation more than FJ would like. His cows do not mind climbing up or down a single slope, but they are not fond of an alternating succession of hills and valleys. FJ would like to add and remove dirt from the road so that it becomes one monotonic slope (either sloping up or down).
You are given N integers A1, ... , AN (1 ≤ N ≤ 2,000) describing the elevation (0 ≤ Ai ≤ 1,000,000,000) at each of N equally-spaced positions along the road, starting at the first field and ending at the other. FJ would like to adjust these elevations to a new sequence B1, . ... , BN that is either nonincreasing or nondecreasing. Since it costs the same amount of money to add or remove dirt at any position along the road, the total cost of modifying the road is
|A1 - B1| + |A2 - B2| + ... + |AN - BN |
Please compute the minimum cost of grading his road so it becomes a continuous slope. FJ happily informs you that signed 32-bit integers can certainly be used to compute the answer.
Input
* Line 1: A single integer: N
* Lines 2..N+1: Line i+1 contains a single integer elevation: Ai
Output
* Line 1: A single integer that is the minimum cost for FJ to grade his dirt road so it becomes nonincreasing or nondecreasing in elevation.
Sample Input
7 1 3 2 4 5 3 9
Sample Output
3
Source
USACO 2008 February Gold 題意: A[i]為輸入序列,B[i]為構造序列. 構造非嚴格單調序列B[i],使sigma | A[i]-B[i] | 最小 引理:構造出的B[i]一定在A[i]中出現過.(感性理解一下) [題解] 最開始想到O(n^3)的dp: f[i]表示B[i]=A[i]時,最小花費. 狀態轉移方程: cost(j,i)表示將j~i中一段變成A[j],剩下的變成A[i](連續的)的最小花費,需要O(n)統計 然後,這個dp是可以優化的: 將A中數字離散化(並去重),f[i][j]表示B[i]=b[j]時的最小花費(b[j]是哈希數組,從小到大排序,與下面AC代碼中的b數組含義相同) 這樣可以用minf數組統計出f[i][1],f[i][2]......f[i][j]中的最小值,可以做到O(1)轉移 狀態轉移方程見代碼.1 #include <cstdio> 2 #include <cstring> 3 #include <algorithm> 4 #define ll long long 5 #define maxn 2001 6 #define mLL 0x7f7f7f7f7f7f7f7f 7 using namespace std; 8 int n,num[maxn]; 9 //f[i]為A[i]與B[i]相同時,構成序列1-i的最小花費 10 ll f[maxn],ans1=mLL,ans2=mLL; 11 int cost(int j,int i){//將j+1~i-1區間內的左邊一部分數改成A[i],右邊一部分改成A[j] 12 int tmp=0; 13 for(int k=j+1;k<i;k++) 14 tmp+=abs(num[k]-num[j]); 15 int ret=tmp; 16 for(int k=i-1;k>j;k--){ 17 tmp=tmp-abs(num[k]-num[j])+abs(num[k]-num[i]); 18 ret=min(ret,tmp); 19 } 20 return ret; 21 } 22 void debug(){ 23 int a,b; 24 while(scanf("%d%d",&a,&b)!=EOF){ 25 printf("%d\n",cost(a,b)); 26 } 27 return; 28 } 29 int main(){ 30 scanf("%d",&n); 31 for(int i=1;i<=n;i++) 32 scanf("%d",&num[i]); 33 memset(f,0x7f,sizeof(f)); 34 f[1]=0; 35 for(int i=1;i<=n;i++)//B[i]=A[i] 36 for(int j=1;j<i;j++) 37 if(num[j]<=num[i]) f[i]=min(f[i],f[j]+cost(j,i)); 38 for(int i=1;i<=n;i++) 39 ans1=min(ans1,f[i]+cost(i,n)); 40 memset(f,0x7f,sizeof(f)); 41 f[1]=0; 42 for(int i=1;i<=n;i++) 43 for(int j=1;j<i;j++) 44 if(num[j]>=num[i]) f[i]=min(f[i],f[j]+cost(i,j)); 45 for(int i=1;i<=n;i++) 46 ans2=min(ans2,f[i]+cost(i,n)); 47 printf("%lld\n",min(ans1,ans2)); 48 // debug(); 49 return 0; 50 }TLE的O(n^3)算法
1 #include <cstdio> 2 #include <cstring> 3 #include <algorithm> 4 #define maxn 2001 5 #define ll long long 6 using namespace std; 7 ll f[maxn][maxn],minf[maxn][maxn],ans=0x7f7f7f7f7f7f7f7f; 8 int n,m,a[maxn],b[maxn];//b:hash 9 void dp(){ 10 memset(f,0x3f,sizeof(f)); 11 memset(minf,0x3f,sizeof(minf)); 12 memset(minf[0],0,sizeof(minf[0])); 13 for(int i=1;i<=n;i++){ 14 for(int j=1;j<=m;j++){//去重後的數字,從小到大排序 15 f[i][j]=min(f[i][j],minf[i-1][j]+abs(a[i]-b[j])); 16 minf[i][j]=min(minf[i][j-1],f[i][j]); 17 } 18 } 19 ans=min(ans,minf[n][m]); 20 } 21 int main(){ 22 scanf("%d",&n); 23 for(int i=1;i<=n;i++) 24 scanf("%d",&a[i]),b[i]=a[i]; 25 sort(b+1,b+1+n); 26 m=unique(b+1,b+1+n)-(b+1); 27 dp(); 28 for(int i=1;i<=m/2;i++) 29 swap(b[i],b[m-i+1]); 30 dp(); 31 printf("%lld\n",ans); 32 return 0; 33 }
[poj3666]Making the Grade