文章目录
0. 前言
最最最经典的绝对值不等式问题,有很多变种。这个题是最裸的模板题了。
1. 排序不等式+贪心
贪心思路:
- 按照商店坐标从小到大排序,选择中位数
证明:
- 假设商店已经按照从小到大排序,记为 x 1 , x 2 , x 3 , . . . , x n x_1, x_2,x_3,...,x_n x1,x2,x3,...,xn,货仓在 x x x 位置。那么可计算得到总的距离之和为 f ( x ) = ∣ x 1 − x ∣ + ∣ x 2 − x ∣ + . . . + ∣ x n − x ∣ + f(x)=\mid x_1 -x\mid+\mid x_2 -x\mid+...+\mid x_n -x\mid+ f(x)=∣x1−x∣+∣x2−x∣+...+∣xn−x∣+简单调整,得: f ( x ) = ( ∣ x 1 − x ∣ + ∣ x n − x ∣ ) + ( ∣ x 2 − x ∣ + ∣ x n − 1 − x ∣ ) + . . . f(x)=(\mid x_1 -x\mid+\mid x_n -x\mid)+(\mid x_2 -x\mid+\mid x_{n-1} -x\mid)+... f(x)=(∣x1−x∣+∣xn−x∣)+(∣x2−x∣+∣xn−1−x∣)+... 由简单的高中数学知识可知, ∣ a − x ∣ + ∣ b − x ∣ \mid a -x\mid+\mid b-x\mid ∣a−x∣+∣b−x∣ 若求其最小值,可以数形结合转化为数轴上有点 a 、 b a、b a、b,再给一点 x x x,求 x x x 到 a 、 b a、b a、b 点的距离之和。则 x x x 可能出现在 a 、 b a、b a、b 点两侧和中间,总共三种位置关系。其中出现在中间的时候距离之和最小,即为 ∣ a − b ∣ \mid a-b\mid ∣a−b∣ 。则简单放缩有: f ( x ) = ( ∣ x 1 − x ∣ + ∣ x n − x ∣ ) + ( ∣ x 2 − x ∣ + ∣ x n − 1 − x ∣ ) + . . . f(x)=(\mid x_1 -x\mid+\mid x_n -x\mid)+(\mid x_2 -x\mid+\mid x_{n-1} -x\mid)+... f(x)=(∣x1−x∣+∣xn−x∣)+(∣x2−x∣+∣xn−1−x∣)+... ≥ ( x n − x 1 ) + ( x n − 1 − x 2 ) . . . \ge (x_n-x_1)+(x_{n-1}-x_2)... ≥(xn−x1)+(xn−1−x2)...等号成立的条件是中位数 x x x 在两点之间,针对所有绝对值不等式等号成立
- 如果是奇数个商店,则排序后直接取到中位数,数组下标从 0 开始,则为
n
−
1
2
\frac {n - 1} 2
2n−1,或者
C++
除法自动向下取整,则 n 2 \frac {n} 2 2n - 如果是偶数个商店,排序后取到左中位数与右中位数均可 n − 1 2 \frac {n - 1} 2 2n−1 或者 n 2 \frac {n} 2 2n
- 统一起来就是, n 2 \frac {n} 2 2n。千万别写成 n 2 − 1 \frac {n} 2 - 1 2n−1…
中位数公式: m i n ∑ i n ∣ A − x i ∣ min\sum_i^n\mid A-x_i\mid min∑in∣A−xi∣ 则, A A A 为 x i x_i xi 的中位数
本题可以拓展为二维求曼哈顿距离可以排序来做,但若是欧几里得距离则是一个经典求费马点的问题,采用的是随机算法,没有一般的优秀求法。
关于这个问题的证明,出了采用绝对值不等式来进行公式证明,还有微扰法可以证明。
将 abs(a[i] - a[n >> 1])
改为 abs(a[i] - a[i >> 1])
也可以 AC
。可以证明
∑
i
=
1
n
a
i
−
a
n
2
=
∑
i
=
1
n
a
i
−
a
i
2
\sum_{i=1}^n a_i-a_\frac n 2=\sum_{i=1}^na_i-a_\frac i 2
i=1∑nai−a2n=i=1∑nai−a2i
代码:
#include <iostream>
#include <algorithm>
using namespace std;
const int N = 1e5+5;
int n;
int a[N];
int main() {
cin >> n;
for (int i = 0; i < n; ++i) cin >> a[i];
sort(a, a + n);
int res = 0;
for (int i = 0; i < n; ++i) res += abs(a[i] - a[n / 2]);
cout << res << endl;
return 0;
}