[总结]中位数及带权中位数问题


一、中位数问题

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. 推导

图片28.png
首先将\(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;
}

pic.png

posted @ 2019-11-09 22:14  Wolfloral  阅读(1248)  评论(0编辑  收藏  举报