题意:给出一个数列长度小于5000,每次操作将数列中的数加1或减1,问最少需要多少步操作可以得到一个不降序列;
分析:可知最少的次数,一定是由原来的数据构成的(据说可以用反证法证),即有原来的数组成的不降子序列中有一个最小的情况;
我们用F[i][j] = min(F[i][j -1] (不包含这一个时),F[i-1][j] + fabs(A[i] - B[j])(包含这一种时));其中B[]代表不重非减序列i,j代表前个数最大为B[j]时的最优情况;
注意:本题数据大,F[][]的过程用到了滚动数组;
1 #include <stdio.h> 2 #include <string.h> 3 #include <stdlib.h> 4 #include <math.h> 5 int A[5001],B[5001],C[5001]; 6 __int64 F[3][5001]; 7 __int64 min(__int64 a,__int64 b) 8 { 9 return a > b ? b:a; 10 } 11 int cmp(const void *a,const void *b) 12 { 13 return *(int *)a - *(int *)b; 14 } 15 int main() 16 { 17 int n,m,i,j,a,b; 18 scanf("%d",&n); 19 for(i = 1;i <= n;i ++) 20 { 21 scanf("%d",&A[i]); 22 C[i] = A[i]; 23 } 24 qsort(C + 1, n, sizeof(C[0]), cmp); 25 B[1] = C[1]; 26 m = 1; 27 for(i = 2; i<= n;i ++) 28 if(C[i] > B[m]) 29 { 30 ++ m; 31 B[m] = C[i]; 32 } 33 F[1][1] = fabs(A[1] - B[1]); 34 for(i = 2;i <= m;i ++) 35 F[1][i] = min(F[1][i -1],fabs(A[1] - B[i])); 36 for(i = 2;i <= n;i ++) 37 { 38 F[i&1][1] = F[1 - (i&1)][1] + fabs(A[i] - B[1]); 39 for(j = 2;j <= m;j ++) 40 F[i&1][j] = min(F[i&1][j - 1],F[1 - i&1][j] + fabs(A[i] - B[j])); 41 } 42 printf("%I64d",F[n&1][m]); 43 return 0; 44 }