中位数——士兵站队 nkoj 3551

来源:互联网 发布:电话网络光端机 编辑:程序博客网 时间:2024/04/28 15:22

Description

      在一个划分成网格的操场上,n个士兵散乱地站在网格点上。网格点用整数坐标(x,y)表示。 
士兵们可以沿网格边往上、下、左、右移动一步,但在同一时刻任一网格点上只能有一名士兵。按照军官的命令,士兵们要整齐地列成一个水平队列,即排列成(x,y),(x+1,y),…,(x+n-1,y)。 

如何选择x和y的值才能使士兵们以最少的总移动步数排成一行。编程计算使所有士兵排成一行需要的最少移动步数。

Input


输入士兵数n,1<=n<=10000。 
接下来n行是士兵的初始位置, 
每行2个整数x 和y,-10000<=x,y<=10000。

分析:

对于有序序列A,我们易知S=|A[1]-k|+|A[2]-k|+...+|A[n]-k|,当 k 为序列 A 的中位数时,S 取最小值。因此对于 y 坐标的确定较简单,找出中位数即可,假设最后所有士兵所处的y坐标为p。即是求|y[1]-p|+|y[2]-p|+...+|y[n]-p|的最小值,则p为y序列的中位数x 方向要排成 x,x + 1,x + 2....x + n-1,换言之,它们最终的 x 坐标一定是相连的(连续的)。只要找到一个确定的点就可以确定新的 x 序列了。假如排好后最左边的坐标为 q,则移动的步数就是|x[0]-q|+|x[1]-(q+1)|+|x[2]-(q+2)|+...+|x[n]-(q+n)|,就是|x[0]-q|+|x[1]-1-q|+|x[2]-2-q|+..+|x[n]-n-q|,变形一下|(x[0]-0)-q|+|(x[1]-1)-q|+|(x[2]-2)-q|+..+|(x[n]-n)-q|我们将(x[i]-i)看成一个新的数字Xi那么 q 为新的 X 序列的中位数。对 x[i] 排序,求出 x[i]-i,再排序,求出q
代码如下:
#include<iostream>#include<cstdio>#include<algorithm>using namespace std;int a[10005];struct point{int  x,y;}s[10050];bool cmpx(point a,point b){return a.x<b.x;}bool cmpy(point a,point b){return a.y<b.y;}int main(){int n,i,k,mid,ans=0;scanf("%d",&n);for(i=1;i<=n;i++)scanf("%d%d",&s[i].x,&s[i].y);sort(s+1,s+1+n,cmpy);mid=s[n/2+1].y;   //一定要注意中位数不是n/2for(i=1;i<=n;i++)ans+=abs(mid-s[i].y);    sort(s+1,s+1+n,cmpx);for(i=1;i<=n;i++)s[i].x-=i;   //处理横坐标sort(s+1,s+1+n,cmpx);mid=s[n/2+1].x;for(i=1;i<=n;i++)ans+=abs(s[i].x-mid);printf("%d",ans);}


0 0