题目地址:
https://leetcode.com/problems/best-position-for-a-service-centre/description/
给定 n n n个平面坐标系的坐标 ( x 0 , y 0 ) , . . . , ( x n − 1 , y n − 1 ) (x_0,y_0),...,(x_{n-1},y_{n-1}) (x0,y0),...,(xn−1,yn−1),求: min ( x , y ) ∑ i ( x i − x ) 2 + ( y i − y ) 2 \min_{(x,y)} \sum_i\sqrt{(x_i-x)^2+(y_i-y)^2} (x,y)mini∑(xi−x)2+(yi−y)2
令 f ( x , y ) = ∑ i ( x i − x ) 2 + ( y i − y ) 2 f(x,y)=\sum_i\sqrt{(x_i-x)^2+(y_i-y)^2} f(x,y)=∑i(xi−x)2+(yi−y)2,其海森矩阵为 H ( f ) = [ ∂ 2 f ∂ x 2 ∂ 2 f ∂ x ∂ y ∂ 2 f ∂ y ∂ x ∂ 2 f ∂ y 2 ] = [ ∑ i ( y i − y ) 2 [ ( x i − x ) 2 + ( y i − y ) 2 ] 3 / 2 ∑ i ( x i − x ) ( y i − y ) [ ( x i − x ) 2 + ( y i − y ) 2 ] 3 / 2 ∑ i ( x i − x ) ( y i − y ) [ ( x i − x ) 2 + ( y i − y ) 2 ] 3 / 2 ∑ i ( x i − x ) 2 [ ( x i − x ) 2 + ( y i − y ) 2 ] 3 / 2 ] H(f) = \begin{bmatrix} \frac{\partial^2 f}{\partial x^2} & \frac{\partial^2 f}{\partial x \partial y} \\ \frac{\partial^2 f}{\partial y \partial x} & \frac{\partial^2 f}{\partial y^2} \end{bmatrix}=\begin{bmatrix} \sum_{i} \frac{(y_i - y)^2}{\left[(x_i - x)^2 + (y_i - y)^2\right]^{3/2}} & \sum_{i} \frac{(x_i - x)(y_i - y)}{\left[(x_i - x)^2 + (y_i - y)^2\right]^{3/2}} \\ \sum_{i} \frac{(x_i - x)(y_i - y)}{\left[(x_i - x)^2 + (y_i - y)^2\right]^{3/2}} & \sum_{i} \frac{(x_i - x)^2}{\left[(x_i - x)^2 + (y_i - y)^2\right]^{3/2}} \end{bmatrix} H(f)=[∂x2∂2f∂y∂x∂2f∂x∂y∂2f∂y2∂2f]= ∑i[(xi−x)2+(yi−y)2]3/2(yi−y)2∑i[(xi−x)2+(yi−y)2]3/2(xi−x)(yi−y)∑i[(xi−x)2+(yi−y)2]3/2(xi−x)(yi−y)∑i[(xi−x)2+(yi−y)2]3/2(xi−x)2 是半正定的,从而 f f f是凸函数,从而 g ( x ) = inf y f ( x , y ) g(x)=\inf_y f(x,y) g(x)=infyf(x,y)对于 x x x来讲也是凸函数。单元凸函数求最小值可以用三分法,而二维凸函数求最小值可以用三分套三分的方法。代码如下:
class Solution {
public:
double getMinDistSum(vector<vector<int>>& ps) {
constexpr double eps = 1e-8;
double l = 0, r = 100.0;
auto get_sum = [&](double x, double y) {
double sum = 0.0;
for (auto& p : ps) {
double a = p[0], b = p[1];
sum += sqrt((x - a) * (x - a) + (y - b) * (y - b));
}
return sum;
};
auto calc = [&](double x) -> double {
double l = 0, r = 100;
while (r - l > eps) {
double y1 = l + (r - l) / 3, y2 = l + (r - l) / 3 * 2;
if (get_sum(x, y1) >= get_sum(x, y2))
l = y1;
else
r = y2;
}
return get_sum(x, l);
};
while (r - l > eps) {
double x1 = l + (r - l) / 3, x2 = l + (r - l) / 3 * 2;
if (calc(x1) > calc(x2))
l = x1;
else
r = x2;
}
return calc(l);
}
};
时间复杂度 O ( log r / ϵ ) O(\log r/\epsilon) O(logr/ϵ), r r r是数据范围,空间 O ( 1 ) O(1) O(1)。