输油管问题变形(中位数)—— 士兵站队问题

【问题描述】

       在一个划分成网格的操场上,n个士兵散乱地站在网格点上。网格点由整数坐标(x,y)表示。

士兵们可以沿网格边上、下、左、右移动一步,但在同一时刻任一网格点上只能有一名士兵。

按照军官的命令,士兵们要整齐地列成一个水平队列,即排列成(x,y),(x+1,y),…,(x+n-1,y)。如何

选择x 和y的值才能使士兵们以最少的总移动步数排成一列。

【编程任务】

       计算使所有士兵排成一行需要的最少移动步数。

【输入格式】

       由文件sol.in提供输入数据。文件的第1 行是士兵数n,1≤n≤10000。接下来n 行是士兵的初始

位置,每行2 个整数x 和y,-10000≤x,y≤10000。

【输出格式】

       程序运行结束时,将计算结果输出到文件sol.out中。文件的第1 行中的数是士兵排成一行需要

的最少移动步数。

【输入样例】

5

1 2

2 2

1 3

3 -2

3 3

题目链接:https://www.luogu.org/problem/P1889

思路:

       设排好之后队伍所占据的行为Y,队头所占位置为(X,Y)。写出计算式,

移项不难得到两个中位数相关的式子。

具体过程不再赘述,详见:

https://www.luogu.org/problemnew/solution/P1889

补充中位数定理相关证明:

1、中位数的性质:

给定一个数列,中位数有这样的性质 :所有数与中位数的绝对差之和最小。

2、中位数性质的简单证明:

         首先,给定一个从小到大的数列x1,x2,……,xn,设x是从x1到xn与其绝对差之和最小的数,

则显然x位于x1与xn之间。那么,由于x1,xn与它们之间的任意一点的距离之和都相等,且都等

于xn-x1,因此接下来可以不考虑x1与xn,而考虑剩下的从x2到x[n-1]的数,同样显然有x必然位

于x2和x[n-1]之间,依次类推,最后得出的结论是x就是该数列中间的那个数,或者是中间的那

两个数之一,而这个数就是中位数。

 结论:数列的中位数就是该数列各个数与其绝对差之和最小的数。

 

PS:这里的多项式中如果没有abs,那么可根据性质:

各变量值与其平均数的离差之和为最小,且等于零。

代码实现:

#include <stdio.h>
#include <string.h>
#include <iostream>
#include <algorithm>
#include <vector>

using namespace std;

const int N = 2e5+100;

int tx[N],ty[N];
int main(){
	
	int n,ans;
	while(scanf("%d",&n)!=EOF){
		
		int x,y,id;
		ans = 0;
		for(int i=1;i<=n;i++){
			scanf("%d%d",&x,&y);
			ty[i]=y;
			tx[i]=x;
		}
		sort(ty+1,ty+1+n);
		//注意x要两次排序,特别注意第一次排序
		//或者注意什么元素怎么分布时取中位数可得最小值 
		sort(tx+1,tx+1+n);
		for(int i=1;i<=n;i++)tx[i]-=i-1;
		sort(tx+1,tx+1+n);
		id = (n-1)/2+1;
		for(int i=1;i<=n;i++){
			ans += abs(tx[i]-tx[id])+abs(ty[i]-ty[id]); 
		}
		printf("%d\n",ans);
	}
	return 0;
}

THE END;

      

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值