Description
在一个划分成网格的操场上,n个士兵散乱地站在网格点上。网格点由整数坐标(x,y)表示。士兵们可 以沿网格边上、下、左、右移动一步,但在同一时刻任一网格点上只能有一名士兵。按照军官的命令,士 兵们要整齐地列成一个水平队列,即排列成(x,y),(x+1,y),...,(x+n-1,y)。如何选择x 和y的值才能使士兵 们以最少的总移动步数排成一行。
计算使所有士兵排成一行需要的最少移动步数。
Format
Input
第1 行是士兵数n,1≤n≤10000。接下来n 行是士兵的初始位置,每行2 个整数x 和y,-10000≤x, y≤10000。
Output
第1行中的数是士兵排成一行需要的最少移动步数。
Samples
输入数据
5
1 2
2 2
1 3
3 -2
3 3
输出数据
8
问题分析
士兵排对分为x方向和y方向 所以我们可以把x和y分开来思考 类似与输油管道问题
对于Y方向
设n个士兵的Y轴坐标分别为:Y1,Y2 …… …… Yn, 他们最后站在同一行上,设目标坐标为Y0,
则n个士兵最终在Y轴的需要移动的总的步数值为S1:
S1=|Y1-Y0|+|Y2-Y0|+ …… …… +|Yn-Y0|
结论:Y0取所有Yi的中间值时可以使得S1达到最小(这个结论可以证明)
对于X方向
(1)首先需要对所有士兵的X轴坐标值进行排序(为了方便就近移动)
(2)然后,按从左至右的顺序依次求出每个士兵所对应的“最终位置”(最优),所移动的步数总和就是X轴方向上需要移动的步数
设排序后n个士兵在X轴坐标为: X1’,X2’ …… …… Xn’
他们最终位置”的X轴坐标值为:X0,X0+1,X0+2 …… …… X0+(n-1)
则n个士兵最终X轴的需要移动的总的步数值为S2:
S2=|X1’-X0| + |X2’-(X0+1)|+… +|Xn’-(X0+n-1)|
经过变换
S2=|X1’-X0|+ |(X2’-1)-X0|+ …+|(Xn’-(n-1))-X0|
注意到公式的形式与Y轴方向上的考虑一样,同样是n个已知数分别减去一个待定数后取绝对值,然后求和
结论:求出x1’, x2’-1,… Xn’-(n-1) 的中位数,即求得X0值,最后算出最优解。
样例代码
#include<bits/stdc++.h>
using namespace std;
int main(){
int i,n,x;
scanf("%d",&n);
pair<int,int> P[n];
int a[n],b[n];
for(i=0;i<n;i++){
cin>>P[i].first>>P[i].second;
a[i]=P[i].first;
b[i]=P[i].second;
}
sort(b,b+n);
int sum=0;
x = b[n/2];
for(i=0;i<n;i++){
sum+=abs(b[i]-x);
}
sort(a,a+n);
for(i=0;i<n;i++){
a[i] = a[i]-i;
}
sort(a,a+n);
x = a[n/2];
for(i=0;i<n;i++){
sum+=abs(a[i]-x);
}
printf("%d",sum);
}