题目描述
在一个划分成网格的操场上,n个士兵散乱地站在网格点上,由整数坐标 (x,y)表示。
士兵们可以沿网格边上、下、左、右移动一步,但在同时刻任一网格点上只能有 1 名士兵。
按照军官的命令,们要整齐地列成个水平队列,即排成队列,即排成 (x,y),(x+1,y), …,(x+n-1,y)。请求出如何选择 x 和 y 的值才能使士兵们以最少的总移动步数排成一列。
输入格式
输入的第一行是一个整数,代表士兵数 n。
第 2 到 (n + 1) 行,每行 2 个整数,第 (i + 1) 行的整数 xi,yi 代表第 i 个士兵的坐标。
输出格式
输出一行一个整数,代表答案。
输入输出样例
输入 #1
5
1 2
2 2
1 3
3 -2
3 3
输出 #1
8
说明/提示
对于 100% 的数据,保证 1≤n≤10000,−10000≤x,y≤10000。
题目分析
该题目可以理解为首先确定纵坐标 y 的位置,将所有士兵都放在一排上,然后再具体调整横坐标 x 的位置,因此,仅需要计算所有士兵分别在 x 轴方向的移动步数以及在 y 轴方向上的移动步数,最后再将二者相加,即可得到最终的答案。
具体实现步骤
首先对所有士兵的纵坐标 y 进行 sort 升序排序,然后取纵坐标 y 的中位数,这样就可以知道将士兵们移动到哪一纵坐标处所需要在 y 轴方向移动的步数最少,计算 y 轴方向移动总步数。
接下来便是计算士兵在 x 轴方向的移动步数,这里我是遍历循环,分别将最左边的士兵放在初始位置位于中间的士兵的 x 坐标减去 n 处,到将最左边的士兵放在初始位置位于中间的士兵的 x 坐标加上 n / 2 处,计算不同方案的士兵在 x 轴方向的移动总步数的最小值。
最后将二者的步数加在一起,便是答案所得
AC代码及注释
#include<iostream>
#include<cmath>
#include<algorithm>
using namespace std;
const int N = 1e4 + 10;
int x[N],y[N];
int main()
{
int n;
int step = 0; //定义step变量用于计算移动步数
int m_count = 0;
cin >> n; //输入士兵人数 n
for(int i = 0;i < n;i ++)
{
cin >> x[i] >> y[i]; //依次输入每一个士兵的横纵坐标
}
sort(x,x + n); //将士兵位置的横坐标排序
sort(y,y + n); //将士兵位置的纵坐标排序
int y_mid , x_mid;
x_mid = x[n / 2]; //计算横坐标中位数
y_mid = y[n / 2]; //计算纵坐标中位数
for(int i = 0;i < n;i ++)
{
step += fabs(y[i] - y_mid); //将每一个士兵进行 y 轴方向的移动
}
for(int i = x_mid - n;i < x_mid + n/2;i ++)
{
int count = 0;
int k = i;
for(int j = 0;j < n;j ++)
{
count += fabs(x[j] - k); //计算士兵 x 轴方向的移动步数
k ++;
}
if(i == x_mid - n) m_count = count;
if(count < m_count) m_count = count; //取移动步数最小值
}
step += m_count; //将 x 轴方向以及 y 轴方向的移动步数相加
cout << step; //输出答案总移动步数
return 0;
}