BZOJ1592: [Usaco2008 Feb]Making the Grade 路面修整

n<=2000个数,把它修改成不上升或不下降序列所要改变的数值总共最小是多少
yy一下可得最后改成的数值肯定是原数组数值中的某一个
感觉一下,相邻两个数如果有冲突要改,那肯定把他们改成两者之一的数才较好,具体证明不会。。
f(i,j)--前i个数,最后一个改为第j小(第j大)的数,答案是多少
f(i,j)=min(f(i-1,k))+abs(a[i]-b[j]),其中1<=k<=j,b[j]为a数组排序后的第j小(大)的数
两次dp即可

 1 #include<cstdio>
 2 #include<cstring>
 3 #include<algorithm>
 4 #include<cstdlib>
 5 #include<cmath>
 6 //#include<iostream>
 7 using namespace std;
 8 
 9 int n;
10 #define maxn 2017
11 int f[maxn][maxn];
12 int a[maxn],b[maxn];
13 const int inf=0x7fffffff;
14 int main()
15 {
16     scanf("%d",&n);
17     for (int i=1;i<=n;i++)
18     {
19         scanf("%d",&a[i]);
20         b[i]=a[i];
21     }
22     int ans=inf;
23     sort(b+1,b+1+n);
24     memset(f[0],0,sizeof(f[0]));
25     for (int i=1;i<=n;i++)
26     {
27         f[i][1]=f[i-1][1]+fabs(a[i]-b[1]);
28         int minf=f[i-1][1];
29         for (int j=2;j<=n;j++)
30         {
31             minf=min(minf,f[i-1][j]);
32             f[i][j]=minf+fabs(a[i]-b[j]);
33         }
34     }
35     for (int i=1;i<=n;i++) ans=min(ans,f[n][i]);
36     for (int i=1;i<=n/2;i++) {int t=b[i];b[i]=b[n-i+1];b[n-i+1]=t;}
37     for (int i=1;i<=n;i++)
38     {
39         f[i][1]=f[i-1][1]+fabs(a[i]-b[1]);
40         int minf=f[i-1][1];
41         for (int j=2;j<=n;j++)
42         {
43             minf=min(minf,f[i-1][j]);
44             f[i][j]=minf+fabs(a[i]-b[j]);
45         }
46     }
47     for (int i=1;i<=n;i++) ans=min(ans,f[n][i]);
48     printf("%d\n",ans);
49     return 0;
50 }
View Code

这题5月份写的,开始不会;6月份考原题,不会;7月份考加强版,把a[i]换成a[i]-i即可,又不会。

很好。

posted @ 2017-07-28 17:05  Blue233333  阅读(252)  评论(0编辑  收藏  举报