forked from kamyu104/LeetCode-Solutions
-
Notifications
You must be signed in to change notification settings - Fork 1
/
best-position-for-a-service-centre.cpp
117 lines (112 loc) · 5.11 KB
/
best-position-for-a-service-centre.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
// Time: O(n * iter), iter is the number of iterations
// Space: O(1)
// see reference:
// - https://en.wikipedia.org/wiki/Geometric_median
// - https://wikimedia.org/api/rest_v1/media/math/render/svg/b3fb215363358f12687100710caff0e86cd9d26b
// Weiszfeld's algorithm
class Solution {
public:
double getMinDistSum(vector<vector<int>>& positions) {
static const double EPS = 1e-6;
pair<double, double> median;
median.first = (accumulate(cbegin(positions), cend(positions), 0.0,
[](const auto& a, const auto& b) {
return a + b[0];
}) / positions.size());
median.second = (accumulate(cbegin(positions), cend(positions), 0.0,
[](const auto& a, const auto& b) {
return a + b[1];
}) / positions.size());
pair<double, double> prev_median = {-1.0, -1.0};
while (prev_median.first < 0 || norm(median, prev_median) * positions.size() > EPS) {
const auto& [stopped, new_median] = geometry_median(positions, median);
if (stopped) {
break;
}
prev_median = median;
median = new_median;
}
return accumulate(cbegin(positions), cend(positions), 0.0,
[this, &median](const auto& a, const auto& b) {
return a + norm(median, pair(b[0], b[1]));
});
}
private:
double norm(const pair<double, double>& p1,
const pair<double, double>& p2) {
return sqrt((p1.first - p2.first) * (p1.first - p2.first) +
(p1.second - p2.second) * (p1.second - p2.second));
}
pair<bool, pair<double, double>> geometry_median(
const vector<vector<int>>& positions,
const pair<double, double>& median) {
pair<double, double> numerator = {0.0, 0.0};
double denominator = 0.0;
for (const auto& p : positions) {
const auto& l = norm(median, pair(p[0], p[1]));
if (!l) {
continue;
}
numerator.first += p[0] / l;
numerator.second += p[1] / l;
denominator += 1 / l;
}
if (denominator == 0.0) {
return {true, {0.0, 0.0}};
}
return {false, {numerator.first / denominator, numerator.second / denominator}};
}
};
// Time: O(n * iter), iter is the number of iterations
// Space: O(1)
class Solution2 {
public:
double getMinDistSum(vector<vector<int>>& positions) {
static const double EPS = 1e-6;
static const vector<pair<int, int>> DIRECTIONS = {{0, 1}, {1, 0}, {0, -1}, {-1, 0}};
pair<double, double> median;
median.first = (accumulate(cbegin(positions), cend(positions), 0.0,
[](const auto& a, const auto& b) {
return a + b[0];
}) / positions.size());
median.second = (accumulate(cbegin(positions), cend(positions), 0.0,
[](const auto& a, const auto& b) {
return a + b[1];
}) / positions.size());
double result = dist(positions, median);
double delta = max((*max_element(cbegin(positions), cend(positions),
[](const auto& x, const auto& y) { return x[0] < y[0]; }))[0],
(*max_element(cbegin(positions), cend(positions),
[](const auto& x, const auto& y) { return x[1] < y[1]; }))[1]) -
min((*min_element(cbegin(positions), cend(positions),
[](const auto& x, const auto& y) { return x[0] < y[0]; }))[0],
(*min_element(cbegin(positions), cend(positions),
[](const auto& x, const auto& y) { return x[1] < y[1]; }))[1]);
while (delta > EPS) {
bool found = false;
for (const auto& [dx, dy] : DIRECTIONS) {
pair<double, double> new_median = {median.first + delta * dx, median.second + delta * dy};
const auto& nd = dist(positions, new_median);
if (nd < result) {
result = nd;
median = new_median;
found = true;
break;
}
}
if (!found) {
delta /= 2.0;
}
}
return result ;
}
private:
double dist(const vector<vector<int>>& positions,
const pair<double, double>& p) {
return accumulate(cbegin(positions), cend(positions), 0.0,
[&p](const auto& a, const auto& b) {
return a + sqrt((p.first - b[0]) * (p.first - b[0]) +
(p.second - b[1]) * (p.second - b[1]));
});
}
};