 /**//*
题意:数轴上有n个点,给出这n个点的坐标,求最少的移动距离使得所有点等距排列(不改变原来的相对顺序)
跟士兵站队类似,但这里两个点之间的距离avg不知道,可以通过枚举出来
考虑到,avg太大也不行,太小也不行,应该是一种抛物线,用三分枚举
设第0个点的新位置为x0,则
_x[i] = x0 + i*avg
移动总距离 sum = ∑|x[i]-_x[i]| = ∑|x[i]-x0-i*avg| = ∑|(x[i]-i*avg)-x0|
设y[i] = (x[i]-i*avg) ,则可以用中位数定理,求出x0 = y[n/2]
*/
#include<iostream>
#include<cmath>
#include<algorithm>
#include<cstdio>
#include<iomanip>

using namespace std;

const double EPS = 1e-8;

double x[410] , y[410] , x0;
int n ;

double cal(double avg)
  {
for(int i = 0; i < n; i++)
y[i] = x[i] - i * avg;
sort(y,y+n);//需要sort
double sum = 0 ;
x0 = y[n/2];
for(int i = 0; i<n;i++)
 {
sum += fabs(y[i]-x0);
}
return sum;
}

int main()
  {
//freopen("in","r",stdin);
while(~scanf("%d",&n))
 {
double left = 0.0 , right = 100000.0;
for(int i = 0 ; i < n ; i++)
 {
scanf("%lf",&x[i]);
}
while(right - left > EPS)
 {
double gap = (right - left)/3;
double m1 = left + gap ;
double m2 = right - gap ;
if(cal(m1) + EPS < cal(m2))right = m2;
else left = m1;
}
printf("%.4f\n",cal(left));
for(int i = 0; i < n;i++)
 {
if(i)putchar(' ');
printf("%.7f",x0+i*left);
}
puts("");
}
return 0;
}
|
|
常用链接
随笔分类
Links
搜索
最新评论

|
|