Description:
平面直角坐标系中给定n个点, 每一次只能将一个点移动一个单位, 求移动的最小次数使得这n个点位于同一水平线上且全部相邻.
Input:
n:点的个数(1<= n <=10000)
接下来i(1<= i <=n)行每行输入第i个点的横纵坐标, 中间空格隔开. (-10000 <= x[i],y[i] <= 10000)
Output:
最小移动的步数
Solution:
先只考虑纵坐标, 对于最两端的点, 同时移动到点连线内的任意一位置所需的距离相同, 且均小于移动到点连线外任意位置的距离.
对于次两端的点也是如此, 以此类推, 想要达到纵坐标上的移动步数的最小值, 只需将这n个点先排序, 再全部移到中位数的点处.
(假定已经对y[]进行了排序)即 y[0] -> y[n / 2], y[1] -> y[n / 2], ......, y[n - 1] -> y[n / 2]; 步数为∑y[i] - y[n / 2];
再来考虑横坐标, 假定移动完成后横坐标最左边的点坐标为 xx
则需要将(注意:这个时候已经对x[]完成了排序, 原本左边的点最后也在左边) //大概是这么说的吧
x[0] -> xx + 0;
x[1] -> xx + 1;
...
x[n - 1] -> xx + (n - 1);
转换后变成
x[0] - 0 -> xx;
x[1] - 1 -> xx;
...
x[n - 1] - ( n - 1) -> xx;
所需的步数为了 ∑abs(x[i] - i - xx);
所需要做的即是找出xx, 观察到x[i] - i -> xx与纵坐标的形式类似. 可以得出, xx 即为将x[i] - i 重新排序后的中间值.
AC code:
#include<cstdio>
#include<cstring>
#include<iostream>
#include<cstdlib>
#include<cmath>
#include<algorithm>
#include<queue>
#include<stack>
#include<set>
#include<map>
#include<functional>
using namespace std;
int x[10000 + 5], y[10000 + 5];
int _x[10000 + 5];
int main()
{
int x_steps = 0, y_steps = 0, ans = 0;
int n;
scanf("%d", &n);
for (int i = 0; i < n; i++)
{
scanf("%d%d", &x[i], &y[i]);
}
sort(x, x + n);
sort(y, y + n);
for (int i = 0; i < n; i++)
{
_x[i] = x[i] - i;
}
sort(_x, _x + n);
for (int i = 0; i < n; i++)
{
y_steps += abs(y[i] - y[n / 2]);
x_steps += abs(x[i] - i - _x[n / 2]);
}
ans = x_steps + y_steps;
printf("%d\n", ans);
return 0;
}
最后, WA了很多次, 一直没找到错在哪, 最后把qsort()换成了sort()就过了, 真心求dalao告知这是为什么...