洛谷 \(P1889\) 士兵站队
问题简述
这道题我们可以换另一种思路去看待它,就容易理解了:
在一个平面上,把 \(n\) 个点排列在一条与 \(x\) 轴平行的直线的整点上,且相邻两点的距离为 \(1\) 。
求一种排列方案,使得这\(n\) 个点到目标位置的 曼哈顿距离和最小。
解法综述
由于是求曼哈顿距离,所以可以将 \(x\) ,\(y\) 分开考虑。
首先,要找到最优的一列(使移动步数最少的一列),其实就是要找一条平行于\(x\)轴的直线,设此直线为\(y=k\),那么,每个点到这条线距离为\(|y_i-k|\),不难发现,当\(k\)是所有点纵坐标的中位数时,距离之和最小。
找到了这条直线之后,又该把每个点移到哪个位置才能使结果最优呢?
可以设最左边的点(第一个点)移动后的位置为\(b\),因为所有点必须排在一条线段上,那么第二个点的移动后的位置即为\(b+1\),第三个移动后的位置为\(b+2\)......以此类推,第\(n\)个点移动后的位置为\(b+n-1\)。
那么横向移动的步数之和为\(|x_0-b|+|x_1-b-1|+|x_2-b-2|+......+|x_{n-1}-b-n+1|\),所以,要使步数之和最小,只需要 再找一次中位数 即可。
\(Code\)
#include <bits/stdc++.h>
using namespace std;
const int N = 10010;
int x[N], y[N];
int n, res;
int main() {
cin >> n;
for (int i = 0; i < n; i++) cin >> x[i] >> y[i];
sort(y, y + n);
sort(x, x + n);
for (int i = 0; i < n; i++) res += abs(y[i] - y[n / 2]); // 对与x轴的一条平等线的最短距离和
for (int i = 0; i < n; i++) x[i] -= i;
sort(x, x + n);
for (int i = 0; i < n; i++) res += abs(x[i] - x[n / 2]);
// 输出
cout << res << endl;
return 0;
}
标签:洛谷,P1889,int,res,++,站队,移动,步数
From: https://www.cnblogs.com/littlehb/p/17714423.html