天天看點

【中位數的應用】郵局設定

【問題描述】

  一些村莊建在一條筆直的高速公路邊上,我們用一條坐标軸來描述這條公路,每個村莊的坐标都是整數,沒有兩個村莊的坐标相同。兩個村莊的距離定義為坐标之差的絕對值。我們需要在某些村莊建立兩個郵局。使每個村莊使用與它距離最近的郵局,建立郵局的原則是:所有村莊到各自使用的郵局的距離總和最小。

【輸入格式】

  第一行: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 ;
}