题目链接:http://poj.org/problem?id=3666、
题目给出一个序列a,要求给出一个序列b使得两个数列每一项相减的绝对值之和最小,这里有一个重要的性质:存在一个满足条件的b,其中的数在a中都出现,可以通过数学归纳法去证明。
然后就是dp的转移,前i个数设定好,并且第i个数是第j大的a中的数,这时的转移方程是dp[i][j]=min{dp[i-1][k]}+abs(a[i]-a'[j]),其中k属于[1,j]。
通过前缀最大值的思想容易优化成O(n^2)
代码:
#include<iostream> #include<cstdio> #include<algorithm> using namespace std; const int maxn = 2020; int a[maxn],b[maxn]; int f[maxn][maxn]; const int inf=0x7fffffff; int n; int dp(){ for(int i=1;i<=n;i++)b[i]=a[i]; sort(b+1,b+n+1); for(int i=1;i<=n;i++){ int minv=inf; for(int j=1;j<=n;j++){ minv=min(minv,f[i-1][j]); f[i][j]=minv+abs(a[i]-b[j]); } } int res=inf; for(int i=1;i<=n;i++)res=min(res,f[n][i]); return res; } int main(){ cin>>n; for(int i=1;i<=n;i++)cin>>a[i]; int res=dp(); reverse(a+1,a+n+1); res=min(res,dp()); cout<<res<<endl; }