目录
- 一、中位数问题
- 1. 问题模型
- 2. 结论
- 3. 推导
- 4. 例题
- 二、带权中位数问题
- 1. 问题模型
- 2. 结论
- 3. 推导
- 4. 例题
一、中位数问题
1. 问题模型
数轴\(x\)上有\(n\)个点,现在给出这\(n\)个点的坐标\(a[i](i\in [1,n])\),让你选择一个点\(k(k\in [1,n])\),使得每个点到点\(k\)的距离之和最小。
2. 结论
点\(k\)为序列的中位数时最优:
若n为奇数,点\(k\)位于a[(n+1)/2]处最优;若n为偶数,点\(k\)位于\(a[n/2]\)或\(a[n/2+1]\)均为
3. 推导
首先将\(a[1]\)~\(a[n]\)排序,假设点\(p\)选在坐标\(q\)处,点\(p\)左侧有\(l\)个点,点\(p\)右侧有\(r\)个点,此时分为两种情况:
\(l\lt r\),若点\(p\)向右移动单位距离,则距离之和减小\((r-l)\)。
\(r\lt l\),若点\(p\)向左移动单位距离,则距离之和减小\((l-r)\)。
因此保证点p的左侧节点和右侧节点数量尽量相等时(即\(l=r\)),距离之和最优。
该结论同样适用于求出最优点\(k\),当点\(k\)的左右两侧节点数相等时为最优解,此时\(k\)就是序列的中位数。此时无论左移或右移点\(k\)都会使结果更差。
4. 例题
[CH0501]货仓选址
描述
在一条数轴上有N家商店,它们的坐标分别为 A[1]~A[N]。现在需要在数轴上建立一家货仓,每天清晨,从货仓到每家商店都要运送一车商品。为了提高效率,求把货仓建在何处,可以使得货仓到每家商店的距离之和最小。
输入格式
第一行一个整数N,第二行N个整数A[1]~A[N]。
输出格式
一个整数,表示距离之和的最小值。
样例输入
4
6 2 9 1
样例输出
12
数据范围与约定
对于100%的数据: N<=100000, A[i]<=1000000
显然,将货仓建于中位数处最优。
Code:
#include<bits/stdc++.h>
#define ll long long
using namespace std;
int n,pos,a[100010];ll ans=0;
int main()
{
scanf("%d",&n);
for(int i=1;i<=n;i++) scanf("%d",&a[i]);
sort(a+1,a+n+1);
if(n&1) pos=(n+1)>>1;
else pos=n>>1;
for(int i=1;i<=n;i++)
ans+=abs(a[pos]-a[i]);
printf("%d",ans);
return 0;
}
二、带权中位数问题
1. 问题模型
数轴\(x\)上有\(n\)个点,现在给出这\(n\)个点的坐标\(a[i](i\in [1,n])\)以及这\(n\)个点的点权\(num[i]\),让你选择一个点\(k(k\in [1,n])\),使得每个点到点\(k\)的距离与点权的乘积之和最小。
2. 结论
满足\(\sum_{i=1}^{k} num[i]\geq tot/2\)时(\(tot\)为所有点权之和)的最小点\(k\)为最优点。
3. 推导
可以把每个节点\(i\)由原来只有一个节点看做有\(num[i]\)个点同时位于坐标\(i\)上,此时我们知道当点\(k\)位于\(tot/2\)的坐标上最优。
4. 例题
抗震救灾
问题描述
这场灾难发生后,国家决定设立研究所研究灾后重建工作,由全国各地派技术人员来参加。因为每个地区所派的技术人员数目不
同,出于节约经费的问题,所以目前还没有决定到底有在哪个地区设置研究所进行研究。假设所有地区都在一条直线上,现在
只知道每个地区与汶川的距离和该地派出技术人员的数目(假设汶川在最左端)。请你编程帮助他们确定在哪个地区建立研究
所可以使所有技术人员集中到该地区的费用总和最小。
输入格式
输入文件每一行描述一个地区的信息(地区数<=5000)。 对于每一行,首先是该地区派出的技术人员数目,紧跟着是这个地区相对于汶川的距离,最后是该地区的名称。(技术人员数<=100,地区的相对距离<=10^31,地区名称长度<=20,数据保证有唯一的解);
输出格式
输出文件只需一行,即研究所设定的地区名称。
Sample Input1
7 9289 shengyan
5 8523 beijing
3 5184 guilin
8 2213 chongqing
10 0 wuhan
Sample Output1
chongqing
Code:
#include<bits/stdc++.h>
#define ll long long
using namespace std;
int n=1;
ll tot,sum=0;
struct node{
ll num,dis;
char name[50];
bool operator < (const node &other) const{
return dis<other.dis;
}
}p[5050];
int main()
{
while(scanf("%lld%lld%s",&p[n].num,&p[n].dis,p[n].name)!=EOF) tot+=p[n].num,n++;
n--;
sort(p+1,p+n+1);
for(int i=1;i<=n;i++){
sum+=p[i].num;
if(sum>=tot/2){
printf("%s\n",p[i].name);
return 0;
}
}
return 0;
}
原文地址:https://www.cnblogs.com/cyanigence-oi/p/11828135.html