Skip to content

Commit d41258a

Browse files
NaimSSadamant-pwn
andauthored
Apply suggestions from code review
Thanks for the reply. I will do the other requested changes separately. Co-authored-by: Oleksandr Kulkov <adamant.pwn@gmail.com>
1 parent 0b3ff55 commit d41258a

File tree

1 file changed

+50
-47
lines changed

1 file changed

+50
-47
lines changed

src/geometry/manhattan-distance.md

Lines changed: 50 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -6,45 +6,45 @@ tags:
66
# Manhattan Distance
77

88
## Definition
9-
Consider we have some points on a plane, and define a distance from point $p$ to $q$ as being the sum of the difference between their $x$ and $y$ coordinates:
9+
For points $p$ and $q$ on a plane, we can define the distance between them as the sum of the differences between their $x$ and $y$ coordinates:
1010

11-
$d(p,q) = |p.x - q.x| + |p.y - q.y|$
11+
$$d(p,q) = |p.x - q.x| + |p.y - q.y|$$
1212

13-
This is informally know as the [Manhattan distance, or taxicab geometry](https://en.wikipedia.org/wiki/Taxicab_geometry), because we can think of the points as being intersections in a well designed city, like manhattan, where you can only move on the streets, as shown in the image below:
13+
Defined this way, the distance corresponds to the so-called [Manhattan (taxicab) geometry](https://en.wikipedia.org/wiki/Taxicab_geometry), in which the points are considered intersections in a well designed city, like Manhattan, where you can only move on the streets horizontally or vertically, as shown in the image below:
1414

1515
<center>![Manhattan Distance](https://upload.wikimedia.org/wikipedia/commons/thumb/0/08/Manhattan_distance.svg/220px-Manhattan_distance.svg.png)</center>
1616

17-
This images show some of the smallest paths from one black point to the other, all of them with distance $12$.
17+
This images show some of the smallest paths from one black point to the other, all of them with length $12$.
1818

19-
There are some interseting tricks and algorithms that can be done with this distance, and we will show some of them here.
19+
There are some interesting tricks and algorithms that can be done with this distance, and we will show some of them here.
2020

21-
## Farthest pair of points in Manhattan Distance
21+
## Farthest pair of points in Manhattan distance
2222

23-
Given $n$ points $P$, we want to find the pair of points $p,q$ that are farther apart, that is, maximize $d(p, q) = |p.x - q.x| + |p.y - q.y|$.
23+
Given $n$ points $P$, we want to find the pair of points $p,q$ that are farther apart, that is, maximize $|p.x - q.x| + |p.y - q.y|$.
2424

25-
Let's think first in one dimension, so $y=0$. The main observation is that we can bruteforce if $|p.x - q.x|$ is equal to $p.x - q.x$ or $-p.x + q.x$, because if we "miss the sign" of the absolute value, we will get only a smaller value, so it can't affect the answer. More formally, we have that:
25+
Let's think first in one dimension, so $y=0$. The main observation is that we can bruteforce if $|p.x - q.x|$ is equal to $p.x - q.x$ or $-p.x + q.x$, because if we "miss the sign" of the absolute value, we will get only a smaller value, so it can't affect the answer. More formally, it holds that:
2626

27-
$|p.x - q.x| = max(p.x - q.x, -p.x + q.x)$
27+
$$|p.x - q.x| = \max(p.x - q.x, -p.x + q.x)$$
2828

29-
So for example, we can try to have $p$ such that $p.x$ has the plus sign, and then $q$ must have the negative sign. This way we want to find:
30-
$max_{p, q \in P}(p.x + (-q.x)) = max_{p \in P}(p.x) + max_{q \in P}( - q.x )$.
29+
So, for example, we can try to have $p$ such that $p.x$ has the plus sign, and then $q$ must have the negative sign. This way we want to find:
30+
$$\max\limits_{p, q \in P}(p.x + (-q.x)) = \max\limits_{p \in P}(p.x) + \max\limits_{q \in P}( - q.x ).$$
3131

3232
Notice that we can extend this idea further for 2 (or more!) dimensions. For $d$ dimensions, we must bruteforce $2^d$ possible values of the signs. For example, if we are in $2$ dimensions and bruteforce that $p$ has both the plus signs we want to find:
3333

34-
$max_{p, q \in P} (p.x + (-q.x)) + (p.y + (-q.y)) = max_{p \in P}(p.x + p.y) + max_{q \in P}(-q.x - q.y)$.
34+
$$\max\limits_{p, q \in P} (p.x + (-q.x)) + (p.y + (-q.y)) = \max\limits_{p \in P}(p.x + p.y) + \max\limits_{q \in P}(-q.x - q.y).$$
3535

3636
As we made $p$ and $q$ independent, it is now easy to find the $p$ and $q$ that maximize the expression.
3737

3838
The code below generalizes this to $d$ dimensions and runs in $O(n \cdot 2^d \cdot d)$.
3939

4040
```cpp
4141
long long ans = 0;
42-
for(int msk=0;msk < (1<<d);msk++){
42+
for (int msk = 0; msk < (1 << d); msk++) {
4343
long long mx = LLONG_MIN, mn = LLONG_MAX;
44-
for(int i=0;i<n;i++){
44+
for (int i = 0; i < n; i++) {
4545
long long cur = 0;
46-
for(int j=0;j<d;j++){
47-
if(msk & (1<<j)) cur += p[i][j];
46+
for (int j = 0; j < d; j++) {
47+
if (msk & (1 << j)) cur += p[i][j];
4848
else cur -= p[i][j];
4949
}
5050
mx = max(mx, cur);
@@ -81,17 +81,19 @@ Here's an image to help visualizing the transformation:
8181
## Manhattan Minimum Spanning Tree
8282

8383
The Manhattan MST problem consists of, given some points in the plane, find the edges that connect all the points and have a minimum total sum of weights. The weight of an edge that connects two points is their Manhattan distance. For simplicity, we assume that all points have different locations.
84-
Here we show a way of finding the MST in $O(n \log{n})$ by finding for each point its nearest neighbor in each octant, as represented by the image below. This will give us $O(n)$ candidate edges, which will guarantee that they contain the MST. The final step is then using some standard MST, for example, [Kruskal algorithm using disjoint set union](https://cp-algorithms.com/graph/mst_kruskal_with_dsu.html).
84+
Here we show a way of finding the MST in $O(n \log{n})$ by finding for each point its nearest neighbor in each octant, as represented by the image below. This will give us $O(n)$ candidate edges, which, as we show below, will guarantee that they contain the MST. The final step is then using some standard MST, for example, [Kruskal algorithm using disjoint set union](https://cp-algorithms.com/graph/mst_kruskal_with_dsu.html).
8585

86-
<center>![8 octants picture](manhattan-mst-octants.png)</center>
87-
*The 8 octants relative to a point S*
86+
<center>![8 octants picture](manhattan-mst-octants.png)
8887

89-
The algorithm show here was first presented in a paper from [H. Zhou, N. Shenoy, and W. Nichollos (2002)](https://ieeexplore.ieee.org/document/913303). There is also another know algorithm that uses a Divide and conquer approach by [J. Stolfi](https://www.academia.edu/15667173/On_computing_all_north_east_nearest_neighbors_in_the_L1_metric), which is also very interesting and only differ in the way they find the nearest neighbor in each octant. They both have the same complexity, but the one presented here is easier to implement and has a lower constant factor.
88+
*The 8 octants relative to a point S*</center>
9089

91-
First, let's understand why it is enough to consider only the nearest neighbor in each octant. The idea is to show that for a point $s$ and any two other points $p$ and $q$ in the same octant, $dist(p, q) < max(dist(s, p), dist(s, q))$. This is important, because it shows that if there was a MST where $s$ is connected to both $p$ and $q$, we could erase one of these edges and add the edge $(p,q)$, which would decrease the total cost. To prove this, we assume without loss of generality that $p$ and $q$ are in the octanct $R_1$, which is defined by: $x_s \leq x$ and $x_s - y_s > x - y$, and then do some casework. The image below give some intuition on why this is true.
90+
The algorithm shown here was first presented in a paper from [H. Zhou, N. Shenoy, and W. Nichollos (2002)](https://ieeexplore.ieee.org/document/913303). There is also another know algorithm that uses a Divide and conquer approach by [J. Stolfi](https://www.academia.edu/15667173/On_computing_all_north_east_nearest_neighbors_in_the_L1_metric), which is also very interesting and only differ in the way they find the nearest neighbor in each octant. They both have the same complexity, but the one presented here is easier to implement and has a lower constant factor.
9291

93-
<center>![unique nearest neighbor](manhattan-mst-uniqueness.png)</center>
94-
*We can build some intuition that limitation of the octant make it impossible that $s$ is closer to both $p$ and $q$ then each other*
92+
First, let's understand why it is enough to consider only the nearest neighbor in each octant. The idea is to show that for a point $s$ and any two other points $p$ and $q$ in the same octant, $d(p, q) < \max(d(s, p), d(s, q))$. This is important, because it shows that if there was a MST where $s$ is connected to both $p$ and $q$, we could erase one of these edges and add the edge $(p,q)$, which would decrease the total cost. To prove this, we assume without loss of generality that $p$ and $q$ are in the octanct $R_1$, which is defined by: $x_s \leq x$ and $x_s - y_s > x - y$, and then do some casework. The image below give some intuition on why this is true.
93+
94+
<center>![unique nearest neighbor](manhattan-mst-uniqueness.png)
95+
96+
*Intuitively, the limitation of the octant makes it impossible that $p$ and $q$ are both closer to $s$ than to each other*</center>
9597

9698

9799
Therefore, the main question is how to find the nearest neighbor in each octant for every single of the $n$ points.
@@ -102,21 +104,22 @@ For simplicity we focus on the NNE octant ($R_1$ in the image above). All other
102104

103105
We will use a sweep-line approach. We process the points from south-west to north-east, that is, by non-decreasing $x + y$. We also keep a set of points which don't have their nearest neighbor yet, which we call "active set". We add the images below to help visualize the algorithm.
104106

105-
<center>![manhattan-mst-sweep](manhattan-mst-sweep-line-1.png)</center>
107+
<center>![manhattan-mst-sweep](manhattan-mst-sweep-line-1.png)
108+
109+
*In black with an arrow you can see the direction of the line-sweep. All the points below this lines are in the active set, and the points above are still not processed. In green we see the points which are in the octant of the processed point. In red the points that are not in the searched octant.*</center>
106110

107-
*In black with an arrow you can see the direction of the line-sweep. All the points below this lines are in the active set, and the points above are still not processed. In green we see the points which are in the octant of the processed point. In red the points that are not in the searched octant.*
111+
<center>![manhattan-mst-sweep](manhattan-mst-sweep-line-2.png)
108112

109-
<center>![manhattan-mst-sweep](manhattan-mst-sweep-line-2.png)</center>
110-
*In this image we see the active set after processing the point $p$. Note that the $2$ green points of the previous image had $p$ in its north-north-east octant and are not in the active set anymore, because they already found their nearest neighbor.*
113+
*In this image we see the active set after processing the point $p$. Note that the $2$ green points of the previous image had $p$ in its north-north-east octant and are not in the active set anymore, because they already found their nearest neighbor.*</center>
111114

112-
When we add a new point point $p$, for every point $s$ that has it in it's octant we can safely assign $p$ as the nearest neighbor. This is true because their distance is $d(p,s) = |x_p - x_s| + |y_p - y_s| = (x_p + y_p) - (x_s + y_s)$, because $p$ is in the north-north-east octant. As all the next points will not have a smaller value of $x + y$ because of the sorting step, $p$ is guaranteed to have the smaller distance. We can then remove all such points from the active set, and finally add $p$ to the active set.
115+
When we add a new point point $p$, for every point $s$ that has it in its octant we can safely assign $p$ as the nearest neighbor. This is true because their distance is $d(p,s) = |x_p - x_s| + |y_p - y_s| = (x_p + y_p) - (x_s + y_s)$, because $p$ is in the north-north-east octant. As all the next points will not have a smaller value of $x + y$ because of the sorting step, $p$ is guaranteed to have the smaller distance. We can then remove all such points from the active set, and finally add $p$ to the active set.
113116

114117
The next question is how to efficiently find which points $s$ have $p$ in the north-north-east octant. That is, which points $s$ satisfy:
115118

116119
- $x_s \leq x_p$
117120
- $x_p - y_p < x_s - y_s$
118121

119-
Because no points in the active set are in the $R_1$ region of another, we also have that for two points $q_1$ and $q_2$ in the active set, $x_{q_1} \neq x_{q_2}$ and $x_{q_1} < x_{q_2} \implies x_{q_1} - y_{q_1} \leq x_{q_2} - y_{q_2}$.
122+
Because no points in the active set are in the $R_1$ region of another, we also have that for two points $q_1$ and $q_2$ in the active set, $x_{q_1} \neq x_{q_2}$ and their ordering implies $x_{q_1} < x_{q_2} \implies x_{q_1} - y_{q_1} \leq x_{q_2} - y_{q_2}$.
120123

121124
You can try to visualize this on the images above by thinking of the ordering of $x - y$ as a "sweep-line" that goes from the north-west to the south-east, so perpendicular to the one that is drawn.
122125

@@ -126,7 +129,7 @@ This means that if we keep the active set ordered by $x$ the candidates $s$ are
126129
In summary we:
127130

128131
- Sort the points by $x + y$ in non-decreasing order;
129-
- For every point, we iterate over the active set starting with the point with the largest $x$ such that $x \leq x_p$, and we break the loop if $x_p - y_p \geq x_s - y_s$. For every valid point $s$ we add the edge $(s,p, dist(s,p))$ in our list;
132+
- For every point, we iterate over the active set starting with the point with the largest $x$ such that $x \leq x_p$, and we break the loop if $x_p - y_p \geq x_s - y_s$. For every valid point $s$ we add the edge $(s,p, d(s,p))$ in our list;
130133
- We add the point $p$ to the active set;
131134
- Rotate the points and repeat until we iterate over all the octants.
132135
- Apply Kruskal algorithm in the list of edges to get the MST.
@@ -140,27 +143,27 @@ struct point {
140143

141144
// Returns a list of edges in the format (weight, u, v).
142145
// Passing this list to Kruskal algorithm will give the Manhattan MST.
143-
vector<tuple<long long,int,int> > manhattan_mst_edges(vector<point> ps){
146+
vector<tuple<long long, int, int>> manhattan_mst_edges(vector<point> ps) {
144147
vector<int> ids(ps.size());
145148
iota(ids.begin(), ids.end(), 0);
146-
vector<tuple<long long,int,int> > edges;
147-
for(int rot = 0; rot < 4; rot++){ // for every rotation
148-
sort(ids.begin(), ids.end(), [&](int i,int j){
149+
vector<tuple<long long, int, int>> edges;
150+
for (int rot = 0; rot < 4; rot++) { // for every rotation
151+
sort(ids.begin(), ids.end(), [&](int i, int j){
149152
return (ps[i].x + ps[i].y) < (ps[j].x + ps[j].y);
150153
});
151-
map<int, int, greater<int> > active; // (xs, id)
152-
for(auto i : ids){
153-
for(auto it = active.lower_bound(ps[i].x); it != active.end();
154-
active.erase(it++)){
154+
map<int, int, greater<int>> active; // (xs, id)
155+
for (auto i : ids) {
156+
for (auto it = active.lower_bound(ps[i].x); it != active.end();
157+
active.erase(it++)) {
155158
int j = it->second;
156-
if(ps[i].x - ps[i].y > ps[j].x - ps[j].y)break;
159+
if (ps[i].x - ps[i].y > ps[j].x - ps[j].y) break;
157160
assert(ps[i].x >= ps[j].x && ps[i].y >= ps[j].y);
158161
edges.push_back({(ps[i].x - ps[j].x) + (ps[i].y - ps[j].y), i, j});
159162
}
160163
active[ps[i].x] = i;
161164
}
162-
for(auto &p : ps){ // rotate
163-
if(rot&1)p.x *= -1;
165+
for (auto &p : ps) { // rotate
166+
if (rot & 1) p.x *= -1;
164167
else swap(p.x, p.y);
165168
}
166169
}
@@ -169,9 +172,9 @@ vector<tuple<long long,int,int> > manhattan_mst_edges(vector<point> ps){
169172
```
170173
171174
## Problems
172-
* [AtCoder Beginner Contest 178E Dist Max](https://atcoder.jp/contests/abc178/tasks/abc178_e)
173-
* [CodeForces 1093G Multidimensional Queries](https://codeforces.com/contest/1093/problem/G)
174-
* [CodeForces 944F Game with Tokens](https://codeforces.com/contest/944/problem/F)
175-
* [AtCoder Code Festival 2017D Four Coloring](https://atcoder.jp/contests/code-festival-2017-quala/tasks/code_festival_2017_quala_d)
176-
* [The 2023 ICPC Asia EC Regionals Online Contest (I) Problem J Minimum Manhattan Distance](https://codeforces.com/gym/104639/problem/J)
177-
* [Petrozavodsk Winter Training Camp 2016 Contest 4](https://codeforces.com/group/eqgxxTNwgd/contest/100959/attachments), Problem B Airports
175+
* [AtCoder Beginner Contest 178E - Dist Max](https://atcoder.jp/contests/abc178/tasks/abc178_e)
176+
* [CodeForces 1093G - Multidimensional Queries](https://codeforces.com/contest/1093/problem/G)
177+
* [CodeForces 944F - Game with Tokens](https://codeforces.com/contest/944/problem/F)
178+
* [AtCoder Code Festival 2017D - Four Coloring](https://atcoder.jp/contests/code-festival-2017-quala/tasks/code_festival_2017_quala_d)
179+
* [The 2023 ICPC Asia EC Regionals Online Contest (I) - J. Minimum Manhattan Distance](https://codeforces.com/gym/104639/problem/J)
180+
* [Petrozavodsk Winter Training Camp 2016 Contest 4 - B. Airports](https://codeforces.com/group/eqgxxTNwgd/contest/100959/attachments)

0 commit comments

Comments
 (0)