题目大意
给出了一列数,要求通过修改某些值,使得最终这列数变成有序的序列,非增或者非减的,求最小的修改量。
分析
首先我们会发现,最终修改后,或者和前一个数字一样,或者和后一个数字一样,这样才能修改量最小。
我们先根据原数列排序,确定元素的大小关系,对应编号为p[i]
dp[i][j] 表示考虑前i个元素,最后元素为序列中 第j小元素的最优解
dp[i][j] = MIN(dp[i-1][k]) + abs(a[i]-a[p[j]]), (0<k<=j)
刚开始以为是o(n^3)的复杂度,后来想想,k值在每次j循环的时候就能确定最小值
1 #include<cstdio> 2 #include<cstring> 3 #include<iostream> 4 #include<algorithm> 5 #include<cmath> 6 #define INF 100000000000000 7 #define maxn 2005 8 using namespace std; 9 int n; 10 typedef long long LL; 11 LL a[maxn],b[maxn]; 12 LL dp[maxn][maxn]; 13 int main() 14 { 15 while(scanf("%d",&n)!=EOF) 16 { 17 for(int i=1; i<=n; i++) 18 { 19 scanf("%I64d",&a[i]); 20 b[i]=a[i]; 21 } 22 sort(b+1,b+1+n); 23 for(int i=1; i<=n; i++) 24 for(int j=1; j<=n; j++) 25 dp[i][j]=INF; 26 for(int j=1; j<=n; j++) 27 { 28 dp[1][j]=(a[1]-b[j]); 29 if(dp[1][j]<0) 30 dp[1][j]=-dp[1][j]; 31 } 32 33 for(int i=2; i<=n; i++) 34 { 35 LL k=dp[i-1][1]; 36 for(int j=1; j<=n; j++) 37 { 38 k=min(dp[i-1][j],k); 39 LL tem=(a[i]-b[j]); 40 if(tem<0) 41 tem=-tem; 42 dp[i][j]=min(dp[i][j],k+tem); 43 // printf("==%I64d ",dp[i][j]); 44 } 45 } 46 LL minn=INF; 47 for(int i=1; i<=n; i++) 48 minn=min(minn,dp[n][i]); 49 printf("%I64d ",minn); 50 } 51 return 0; 52 }