sgu 524 Buoys(三分+中位数定理)

【题目大意】:给出n个点,要求移动最小的距离,使得点的间距相等。

 

【解题思路】:暑假写练习赛的题目,一下的东西是去年写的题解,现在开始搬博客。

一开始觉得像二分距离,问题是没有单调性。仔细想想,发现其实这个距离是不可以太大也不可以太短,好像是存在峰值的。好像是,因为木有写过三分。

然后,开始yy。发现sum=|x1-y1|+|x2-y2|+....|xn-yn|   x数组是原来给出的点的坐标,y是后面得到等距的点的坐标。那么根据等差序列可以化成

sum=|x1-a-0*d|+|x2-a-1*d|+....+|xn-a-(n-1)*d|。接着,变一下,就是sum=|x1-0*d-a|+|x2-1*d-a|+.....+|xn-(n-1)*d-a|

感觉有点像求min{sum},(其实是中位数定理)所以试着带了点数据进去是了一下,发现a只要取中间的那个数,sum就可以达到最小。好像是可以根据绝对值不等式证明吧,没有试过。

最后,上机yy,就过了。其实这道题是我人生的人生第一道三分


#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <vector>
#include <queue>
#include <cmath>
#include <string>
#include <cctype>
#include <map>
#include <iomanip>
                   
using namespace std;
                   
#define eps 1e-8
#define pi acos(-1.0)
#define inf 1<<30
#define pb push_back
#define lc(x) (x << 1)
#define rc(x) (x << 1 | 1)
#define lowbit(x) (x & (-x))
#define ll long long

double a,x[450],xx[450];    
int n;

double ABS(double k)  {  
    if (k<0) return -k; else return k;  
}  
  
double check(double s)  {  
    for (int i=0; i<n; i++) xx[i]=x[i]-i*s;  
    sort(xx,xx+n);  
    double sum=0.0;  
    a=xx[n/2];  
    for (int i=0; i<n; i++)  
        sum+=ABS(xx[i]-a);  
    return sum;  
}  
  
int main()  {  
    while (~scanf("%d",&n)) {  
        for (int i=0; i<n; i++)  
            scanf("%lf",&x[i]);  
        double low=0.0,high=200000.0,mmid,mid;  
        double ans,ans1,ans2,k2,k1;  
        while (low+eps<high)  {  
            mid=(low+high)/2.0;  
            mmid=(mid+high)/2.0;  
            k1=check(mid);  
            k2=check(mmid);  
            if (k1<=k2)   {  
                ans=k1;  
                high=mmid;  
                ans1=a;  
                ans2=mid;  
            }  
            else  {  
                ans=k2;  
                low=mid;  
                ans1=a;  
                ans2=mmid;  
            }  
        }  
        printf("%.4f\n",ans);  
        for (int i=0; i<n-1; i++)  
            printf("%.7f ",ans1+i*ans2);  
        printf("%.7f\n",ans1+(n-1)*ans2);  
    }  
    return 0;  
}  


你可能感兴趣的:(sgu 524 Buoys(三分+中位数定理))