在一个划分成网格的操场上,n个士兵散乱地站在网格点上。网格点用整数坐标(x,y)表示。士兵们可以沿网格边往上、下、左、右移动一步,但在同一时刻任一网格点上只能有一名士兵。按照军官的命令,士兵们要整齐地列成一个水平队列,即排列成(x,y),(x+1,y),…,(x+n-1,y)。如何选择x和y的值才能使士兵们以最少的总移动步数排成一行。
编程计算使所有士兵排成一行需要的最少移动步数。
题目引自POJ
输入格式:
第1行是士兵数n,1≤n≤10000。接下来n行是士兵的初始位置,每行有2个整数x和y,-10000≤x,y≤10000。
输出格式:
一个数据,即士兵排成一行需要的最少移动步数。
输入样例:
5
1 2
2 2
1 3
3 -2
3 3
输出样例:
8
代码长度限制
16 KB
时间限制
400 ms
内存限制
64 MB
栈限制
8192 KB
因为是在坐标网格内移动,想要移动步数最小,x方向移动的步数和y方向上移动的步数必须满足终点坐标减起始坐标,那么想要求总移动步数最小我们可以把x坐标的移动次数和y坐标的移动次数分别求解然后相加,就能得出最少的总移动步数。
在Y轴上,想要某点到所有y坐标的距离和最小即找一个坐标Y_min,使得sumY=|y0-Y_min| + |y1-Y_min| + |y2-Y_min|....|yn-1-Y_min|。对于Y_min如何寻找,我们可用数学方法解的Y_min就是全体y坐标按照升序排列的中位数。
在X轴上,假设按照升序排列后的x坐标序列为x0、x1、x2......xn-1,最后站好时的x坐标序列为a0、a1、a2......an-1,所以sumX= |x0-a0| + |x1-a1| + |x2-a2|....+| xn-1-an-1|。又因为士兵站好时在x轴上是连续的所以a1=a0+1,a2=a0+2.....an-1=a0+n-2,所以上式可化为sumX= |x0-a0| + |x1-1-a0| + |x2-2-a0|....+| xn-1-(n-1)-a0|此时可以看出x轴上移动最少次数的问题就变成了x0、x1-1、x2-2......xn-1-(n-1)这些点的集合与a0的距离最小值,与Y轴的求解方法类似先进行升序排序,当a0等于排序后的中位数时sumX最小。
代码如下:
#include<bits/stdc++.h>
using namespace std;
int main()
{
int res=0;
int x[10001]={0},y[10001]={0};
int n;
cin>>n;
for(int i=0;i<n;i++)
cin>>x[i]>>y[i];
sort(x,x+n);
for(int i=0;i<n;i++)
x[i]=x[i]-i;
sort(x,x+n);
sort(y,y+n);
for(int i=0;i<n;i++)
{
res+=abs(y[i]-y[n/2]);
res+=abs(x[i]-x[n/2]);
}
cout<<res<<endl;
return 0;
}