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/2 for(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); }