中位数应用,那些未指明权值的默认权值为1,定义+例题,看完别说你还不懂!!!
中位数,编程问题中即n/2位置处的数,主要用的是带权中位数,带权中位数(Weighted Median),
其定义和中位数的差别在于:
中位数:n个元素集合中,第n/2小的元素。
带权中位数:对于n个互不相同的元素集合x1、x2……xn,其权重依次为w1、w2……wn。令W =
sigma(wi),则带权中位数xk满足:
sigma(wi)(xi<XK)
sigma(wi)(xi>xk)<=W/2
其中sigma表示求和。
带权中位数xk满足:sigma(|xi-xk|*wi)最小。
应用一:
仓库选址
★问题描述
在一个直线的公路上,有n个连锁超市,为了便于物流管理,物流公司决定在公路上
建立一个仓库,为这些超市供货。
已知n个超市在公路上的坐标依次为x1, x2, …, xn,每天需要的货物数量依次为w1, w2,
…, wn, 假设在公路上坐标为xp的地点建立仓库,那么仓库为超市的供货费用依次为w1*|x1-xp|,
w2*|x2-xp|, …, wn*|xn-xp|。
★编程任务
在公路上选择一个位置xp建立仓库,使得仓库为超市供货的总费用最小。
★数据输入
由文件input.txt提供输入数据。输入第一行为一个整数n,表示公路上超市的个数。接下
来n行,每行两个整数表示xi和wi。(1 ≤ n,xi,wi ≤ 1,000,000)
★数据输出
将程序运行结果输出到文件output.txt中。输出一行一个整数,表示仓库每天为超市供
货的最小费用。
view plaincopy to clipboardprint?
1. input:
2.
3. 3
4. 1 3
5. 2 2
6. 3 1
7.
8. output:
9.
10. 4
11. 解法:
12. 将输入的数据按x排序,若x相等则按需要货物的多少排序,结构体内重载了<运算符。然后寻找所谓
13.
14. 的带权中位数,即***语句,然后计算最小费用。
15. code:
16. #include
17. #include
18. #include
19. using namespace std;
20. const int nax=10010;
21. int coun=0;
22. int label[2*nax];
23. typedef struct sd
24. {
25. int x;
26. int v;
27. bool operator<(const struct sd &tmp) const//从小到大排
28. {
29. if(x<TMP.X)&NBSP;< span>return true;
30. if(x>tmp.x) return false;
31. return v<TMP.V;&NBSP;&NBSP;< span>
32. };
33. }pzj;
34. pzj pzjay[nax];
35. int main()
36. {
37. int n,i,suma=0,sumb=0;
38. scanf("%d",&n);
39. for(i=0;i<N;++I)&NBSP;&NBSP;< span>
40. {
41. scanf("%d%d",&pzjay[i].x,&pzjay[i].v);
42. suma+=pzjay[i].v;
43. }
44. sort(pzjay,pzjay+n);
45. for(i=0;sumb+pzjay[i].v<>//***
46. sumb+=pzjay[i].v;
47. int ans=0;
48. while(n--)
49. ans+=abs(pzjay[n].x-pzjay[i].x)*pzjay[n].v;
50. printf("%d/n",ans);
51. }
应用二:
邮局选址
☆问题描述:
在一个坐标图上坐落着一个美丽的村庄——王岗(囧),那里的村民过着和平宁静的生活。村民家的
家庭住址在坐标图上用(x,y)表示,x,y均是不小于0的整数。一天村长宣布要在村里放一个邮箱,
让聪明的村民提供方案,放在什么位置能让各位村民取邮件时走路的总距离(定义:|X1-X2|+|Y1-
Y2|)最短,王岗村的村民果然不负众望,选出了一个最公平的方案,你知道最短是多少么?
输入:
输入数据的第一行是一个整数n(1,10000),表示村民家的数量;接下来n行,每行2 个整数x 和y
,-10000<=x,y<=10000。
输出
程序运行结束时,将计算结果输出。第1 行中的数是n 个居民点到邮局的距离总和的最小值。
view plaincopy to clipboardprint?
1. 样例输入
2.
3. 5
4. 1 2
5. 2 2
6. 1 3
7. 3 -2
8. 3 3
9.
10. 样例输出
11.
12. 10
13. 解法:
14. 赤裸裸的中位数应用呀:这里由距离的特殊定义可知x,y可以分别考虑,拿x为例(y同此),x排序
15.
16. ,对头尾居民来说,到邮局(带权中位数)处的距离和为(Xn-X1)——邮局(就是那个最近的点)肯
17.
18. 定在二者中间,X2到Xn-1同理,故n为奇数时,邮局的x坐标为中间的数,n为偶数时,处于中间的两
19.
20. 个数任选其一。最后得到x=(x(n/2+1)+x(n/2+2)+...+xn)-(x1+x2+..+x(n/2))
21. 放码子
22. #include<iostream>
23. #include<algorithm>
24. using namespace std;
25. int ans;
26. int pzjay(int a[],int n)
27. {
28. ans=0;
29. int mid=a[n/2],i;
30. for(i=0;i<n;++i)
31. ans+=abs(a[i]-mid);
32. return ans;
33. }
34. int main()
35. {
36. int i,n;
37. scanf("%d",&n);
38. int *x,*y;
39. x=new int[n+1];
40. y=new int[n+1];
41. for(i=0;i<n;++i)
42. scanf("%d%d",x+i,y+i);
43. sort(x,x+n);
44. sort(y,y+n);
45. printf("%d/n",pzjay(x,n)+pzjay(y,n));
46. return false;
47. }
应用三:
士兵移动问题:http://acm.pku.edu.cn/JudgeOnline/problem?id=1723(题目)
解法:(偶山寨别人的)
最终士兵停在的水兵线的坐标ymid即为所有坐标的中位数,ymid 是 队伍的 位置没错了,
但是 xmid 不是 队伍的中心哦。
假设 n个士兵的 x 坐标是, x0,x1,.. x(n-1)
我们假设 他们 是 递增序列。
假设排好的队伍的 最左边的 x 坐标是 xl
那么我们的任务是 使
|xl-x0| + |xl+1-x1| +.... + | xl+n-1 -x(n-1) | 的值最小,
这个 表达式的 极值可不一定是取在 xl = xmid-n/2 的时候~
这个时候我们取 xnewmid 为
x0, x1-1, x2-2... x(n-1) - (n-1)
的平均值,
然后 使 xl = xnewmid
|xl-x0| + |xl+1-x1| +.... + | xl+n-1 -x(n-1) |
再加上 |Yi - ymid| 的总和 才是答案
view plaincopy to clipboardprint?
1. code:
2. #include<iostream>
3. #include<cmath>
4. #include<algorithm>
5. using namespace std;
6. int main()
7. {
8. int n,*x,*y,i;
9. int ans=0;
10. scanf("%d",&n);
11. x=new int[n+1];
12. y=new int[n+1];
13. for(i=0;i<n;++i)
14. scanf("%d%d",x+i,y+i);
15. nth_element(y,y+n/2,y+n);//找到目标中位数放到中间,也可用排序实现
16. int tmpy=y[n/2];
17. sort(x,x+n);
18. for(i=0;i<n;++i)
19. x[i]-=i;
20. nth_element(x,x+n/2,x+n);
21. int tmpx=x[n/2];
22. while(n--)
23. ans+=abs(x[n]-tmpx)+abs(y[n]-tmpy);
24. printf("%d/n",ans);
25. return false;
26. }
27. 这T刚开始STL模拟了半天被越来越多的情况卡死后百度中位数知识心生感触偶为此文发表的说— —
28.
29. bbb。
应用四:
题目描述:http://www.vijos.cn/Problem_Show.asp?id=1036
解法:看代码咯。。。
//这个代码纯属拷贝,同时学习,好靓滴哦
view plaincopy to clipboardprint?
1. #include<iostream>
2. #include<algorithm>
3. using namespace std;
4. typedef struct pp
5. {
6. int x;
7. int y;
8. int need;
9. }MM;
10. MM mm[10000];
11. int n;
12. bool cmp_x(MM a,MM b)
13. {
14. return a.x<b.x ||(a.x==b.x && a.y<b.y);
15. }
16. bool cmp_y(MM a,MM b)
17. {
18. return a.y<b.y ||(a.y==b.y && a.x<b.x);
19. }
20. bool input()
21. {
22. int i,peo,ned;
23. if(EOF==scanf("%d",&n))
24. return false;
25. for(i=0;i<n;++i)
26. {
27. scanf("%d%d%d%d",&mm[i].x,&mm[i].y,&peo,&ned);
28. mm[i].need=peo*ned;
29. }
30. return true;
31. }
32. int get(bool(*cmp)(MM,MM))//获取带权中位数
33. {
34. sort(mm,mm+n,cmp);
35. int i,sum=0;
36. for(i=0;i<n;++i)
37. sum+=mm[i].need;
38. int k=0,s=0;
39. while(s+mm[k].need<sum/2)
40. {
41. s+=mm[k].need;
42. ++k;
43. }
44. return k;
45. }
46. int main()
47. {
48. while(input())
49. {
50. int mid=get(cmp_x);//获得x的带权中位数
51. int mid_x=mm[mid].x;
52. mid=get(cmp_y);//获得y的带权中位数
53. int mid_y=mm[mid].y;
54. printf("%d %d/n",mid_x,mid_y);
55. }
56. return false;
57. }
58. /*
59. input:
60. 5
61. 2 3 5 3
62. 2 1 100 30
63. 2 2 1 1
64. 3 2 7 6
65. 1 1 4 30
66. output:
67. 2 1
68.
69.
70. */
应用五:
抗震救灾:
汶川地震发生后,国家决定设立研究所研究灾后重建工作,由全国各地派技术人员来参加。因为每个
地区所派的技术人员数目不同,出于节约经费的问题,所以目前还没有决定到底有在哪个地区设置研
究所进行研究。假设所有地区都在一条直线上,现在只知道每个地区与汶川的距离和该地派出技术人
员的数目(激射汶川在最左端)。请你编程帮助他们确定在哪个地区建立研究所可以使所有技术人员
集中到该地区的费用总和最小。
输入文件每一行描述一个地区的信息(地区数<=5000)。
对于每一行,首先是该地区派出的技术人员数目,紧跟着是这个地区相对于汶川的距离,最后是该地
区的编号。(技术人员数<=100,地区的相对距离<=10^9(本来是31次方,为了突出中位数的重点,就
改小了),数据保证有唯一的解);
view plaincopy to clipboardprint?
1. input:
2. 5
3. 7 9289 1
4. 5 8523 2
5. 3 5184 3
6. 8 2213 4
7. 10 0 5
8. output:
9. 4
10. 放码子:
11. #include<iostream>
12. #include<algorithm>
13. using namespace std;
14. typedef struct pp
15. {
16. int peo;
17. int dis;
18. int num;
19. bool operator<(const struct pp &tmp)const//按距离排序,距离相等按人数
20. {
21. if(dis!=tmp.dis)
22. return dis<tmp.dis;
23. return peo<tmp.peo;
24. }
25. }MM;
26. MM plmm[1000];
27. int main()
28. {
29. int n,i;
30. scanf("%d",&n);
31. int suma=0;
32. for(i=0;i<n;++i)
33. {
34. scanf("%d%d%d",&plmm[i].peo,&plmm[i].dis,&plmm[i].num);
35. suma+=plmm[i].peo;
36. }
37. sort(plmm,plmm+n);
38. int sum=0;
39. for(i=0;sum+plmm[i].peo<suma/2;++i)
40. sum+=plmm[i].peo;
41. printf("%d/n",plmm[i].num);
42. return false;
43. }