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 <algorithm>
#include <cstring>
#include <string>

using namespace std;

#define eps 1e-8

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;
}


 

【运行结果】:

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值