Codeforces 13C(DP)

题意:给出一个数列长度小于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 }
View Code
原文地址:https://www.cnblogs.com/AHU-songyuan2235/p/3356182.html