题目描述
题目分析
这一道题本人一开始看还以为是贪心。
其实正解是一个很普通的DP。
首先,我们设一个
f[i][j]
为前i棵树,前j只猴子的答案。
于是我们便可以得到一个状态转移方程:
f[i][j]=min(f[i−1][j−1],f[i][j−1])+abs(a[i]−b[j])
其中 a[i] 是第i只猴子的坐标, b[j] 是第j棵树的坐标。
但题目非常好地提醒了我们注意空间是否超限。
因为我们发现前i棵树的答案只与前i-1棵树的答案有关联。
所以我们开个滚动数组即可。
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<cmath>
using namespace std;
long long a[5100],b[5100];
long long f[5100][2];
int cmp(const void *xx,const void *yy)
{
long long n1=*(long long *)xx;
long long n2=*(long long *)yy;
if(n1>n2) return 1;
else return -1;
}
long long mymin(long long x,long long y) {return x<y?x:y;}
int main()
{
int n,m;
scanf("%d",&n);
for(int i=1;i<=n;i++)
{
scanf("%lld",&a[i]);
}
scanf("%d",&m);
for(int i=1;i<=m;i++)
{
scanf("%lld",&b[i]);
}
qsort(a+1,n,sizeof(long long),cmp);
qsort(b+1,m,sizeof(long long),cmp);
memset(f,0,sizeof(f));
for(int i=0;i<=n;i++)
{
f[i][0]=f[i][1]=999999999999999999;
}
int l=1;f[0][1]=0;
for(int i=1;i<=m;i++)
{
l=1-l;
for(int j=0;j<=n;j++)
{
f[j][l]=999999999999999999;
}
for(int j=1;j<=n;j++)
{
f[j][l]=mymin(f[j-1][1-l],f[j-1][l])+abs(b[i]-a[j]);
}
}
printf("%lld\n",f[n][l]);
return 0;
}