【问题描述】
在一个划分成网格的操场上,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)。写出计算式,
移项不难得到两个中位数相关的式子。
具体过程不再赘述,详见:
补充中位数定理相关证明:
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;