天天看点

【中位数的应用】邮局设置

【问题描述】

  一些村庄建在一条笔直的高速公路边上,我们用一条坐标轴来描述这条公路,每个村庄的坐标都是整数,没有两个村庄的坐标相同。两个村庄的距离定义为坐标之差的绝对值。我们需要在某些村庄建立两个邮局。使每个村庄使用与它距离最近的邮局,建立邮局的原则是:所有村庄到各自使用的邮局的距离总和最小。

【输入格式】

  第一行:n ,表示有n个村庄。

  第二行:a1 a2 a3 .. an 表示n个村庄的坐标。

【输出格式】

  第一行:表示最小距离总和。

【输入样例】

10
1 2 3 6 7 9 11 22 44 50
           

【输出样例】

43
           

【数据范围】

1<=n<=10000  
1<=a[i]<=1000000000
           

题目大意:给了你x轴上一些点的坐标,要求你选取其中的两个点使得其他点到这两个点的距离总和最小。

算法:中位数的应用+枚举

乍一看不好求,但是如果题目只需要求一个点,那么显然由中位数原理知这个点是所有点的中位点。然而这个题要求修两个点的情形,该怎么办呢?

这里有一种思路:把全部点按坐标从小到大排序后,分成两个部分,那么这两个部分的中位点建立邮局显然使这两个部分中的所有点都有到邮局的最小值,枚举这两个部分的中间点i,求出两个部分的最小距离并取最小值就是答案。

【中位数的应用】邮局设置
#include<cstdio>
#include<iostream>
#include<cstring>
#include<queue>
#include<algorithm>
#include<cmath>
#include<cstdlib>
using namespace std;
typedef long long LL;
const int maxn=;
const LL inf=;
int n;
int A[maxn];
int main()
{
    //freopen("my.in","r",stdin);
    //freopen("my.out","w",stdout);

    scanf("%d",&n);
    for(int i=;i<=n;i++)
    scanf("%d",&A[i]);

    sort(A+,A++n);

    int mp1=,mp2=;
    LL sum,ans=inf;
    for(int i=;i<=n;i++)
    {
        mp1=A[(i+)/];
        mp2=A[(i+n+)/];
        sum=;

        for(int j=;j<=i;j++)
        sum+=abs(A[j]-mp1);

        for(int j=i+;j<=n;j++)
        sum+=abs(A[j]-mp2);

        ans=min(sum,ans);
    }

    cout<<ans<<endl;

    return ;
}