-
Notifications
You must be signed in to change notification settings - Fork 496
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Update Eulers_Formula.mdx #4801
Changes from 1 commit
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change | ||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
@@ -1,7 +1,7 @@ | ||||||||||||||||||
--- | ||||||||||||||||||
id: eulers-formula | ||||||||||||||||||
title: "Euler's Formula" | ||||||||||||||||||
author: Benjamin Qi | ||||||||||||||||||
author: Benjamin Qi, Aarush Penugonda | ||||||||||||||||||
description: A formula for finding the number of faces in a planar graph. | ||||||||||||||||||
prerequisites: | ||||||||||||||||||
- dsu | ||||||||||||||||||
|
@@ -11,19 +11,215 @@ frequency: 1 | |||||||||||||||||
|
||||||||||||||||||
## Introduction | ||||||||||||||||||
|
||||||||||||||||||
<IncompleteSection /> | ||||||||||||||||||
A planar graph is a graph that can be drawn on a plane without any edges crossing. In other words, it can be embedded in the plane such that no two edges intersect except at their endpoints. Planar graphs can be represented in a two-dimensional space without overlaps between edges. | ||||||||||||||||||
|
||||||||||||||||||
<Resources> | ||||||||||||||||||
<Resource | ||||||||||||||||||
source="MIT" | ||||||||||||||||||
title=" MIT Course Notes" | ||||||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. weird formatting |
||||||||||||||||||
url="https://dspace.mit.edu/bitstream/handle/1721.1/104426/6-042j-spring-2010/contents/readings/MIT6_042JS10_chap12.pdf" | ||||||||||||||||||
|
||||||||||||||||||
> | ||||||||||||||||||
6.024J course notes | ||||||||||||||||||
</Resource> | ||||||||||||||||||
<Resource | ||||||||||||||||||
source="Wiki" | ||||||||||||||||||
title="Planar Graph" | ||||||||||||||||||
url="https://en.wikipedia.org/wiki/Planar_graph" | ||||||||||||||||||
> | ||||||||||||||||||
Wiki Definition | ||||||||||||||||||
</Resource> | ||||||||||||||||||
<Resource | ||||||||||||||||||
source="Rutgers" | ||||||||||||||||||
title="Planar Graph" | ||||||||||||||||||
url="https://sites.math.rutgers.edu/~sk1233/courses/graphtheory-F11/planar.pdf" | ||||||||||||||||||
/> | ||||||||||||||||||
|
||||||||||||||||||
</Resources> | ||||||||||||||||||
|
||||||||||||||||||
## Euler's Formula | ||||||||||||||||||
|
||||||||||||||||||
Euler's Formula states that any correct embedding of a connected planar graph satistfies:- | ||||||||||||||||||
|
||||||||||||||||||
<center><h1>V − E + F = 2</h1></center> | ||||||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. use double dollar signs for latex |
||||||||||||||||||
|
||||||||||||||||||
Where V is the no of vertices, E is the number of edges and F is the number of faces. | ||||||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. use latex for these variables |
||||||||||||||||||
|
||||||||||||||||||
## Example 1 | ||||||||||||||||||
|
||||||||||||||||||
<Problems problems="e1" /> | ||||||||||||||||||
## Explanation | ||||||||||||||||||
|
||||||||||||||||||
### Intuition | ||||||||||||||||||
|
||||||||||||||||||
In this problem, we're asked to count the number of contiguous areas of cells on | ||||||||||||||||||
several flat rectangles. Such areas are separated by river segments and | ||||||||||||||||||
rectangle boundaries. | ||||||||||||||||||
|
||||||||||||||||||
Where else do we count the number of areas on a flat surface? | ||||||||||||||||||
Comment on lines
+59
to
+63
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
wording is confusing on this part. it might be better to not restate the problem at all |
||||||||||||||||||
|
||||||||||||||||||
That's right - we use Euler's formula to count the number of faces of a | ||||||||||||||||||
[planar graph](http://discrete.openmathbooks.org/more/mdm/sec_planar.html). This | ||||||||||||||||||
suggests that we should turn our rectangles into planar graphs. | ||||||||||||||||||
|
||||||||||||||||||
### Making the Planar Graph | ||||||||||||||||||
|
||||||||||||||||||
We can turn a rectangle into a planar graph as so: | ||||||||||||||||||
|
||||||||||||||||||
- Put temporary river segments outside the border of the rectangle. | ||||||||||||||||||
- For each river segment, we insert its 4 corners into a set of nodes and its 4 | ||||||||||||||||||
sides into a set of edges. | ||||||||||||||||||
|
||||||||||||||||||
Notice how the resulting graph is planar, so we can apply Euler's formula. | ||||||||||||||||||
|
||||||||||||||||||
### Applying Euler's Formula | ||||||||||||||||||
|
||||||||||||||||||
For a planar graph, Euler's formula is given as $F = E - V + 1 + C$, where $F$ | ||||||||||||||||||
is the number of faces (including the background face), $E$ is the number of | ||||||||||||||||||
edges, $V$ is the number of vertices, and $C$ is the number of connected | ||||||||||||||||||
components. | ||||||||||||||||||
|
||||||||||||||||||
Notice how $F$ in our planar graph is equal to $1 + R + A$, where $R$ is the | ||||||||||||||||||
number of river segments and $A$ is the answer to the query. This means we must | ||||||||||||||||||
subtract $R + 1$ from $F$ to get $A$. | ||||||||||||||||||
|
||||||||||||||||||
Since the whole river is a big connected component, we can just check whether | ||||||||||||||||||
the river touches the bounding rectangle to determine $C$. | ||||||||||||||||||
|
||||||||||||||||||
Finding $E$, $V$, and $R$ is a lot more complicated though. | ||||||||||||||||||
|
||||||||||||||||||
### Finding $E$, $V$, and $R$ | ||||||||||||||||||
|
||||||||||||||||||
To find $E$, $V$, and $R$, we can use a data structure that can handle 2D range | ||||||||||||||||||
queries efficiently. | ||||||||||||||||||
|
||||||||||||||||||
However, the coordinates of the grid can get very large, so a simple 2D BIT or | ||||||||||||||||||
segment tree won't work here. | ||||||||||||||||||
|
||||||||||||||||||
To work around this, we can either use a 2D BIT with coordinate compression or a | ||||||||||||||||||
persistent segment tree. See the sections on | ||||||||||||||||||
[offline 2D sum queries](/plat/2DRQ#2d-offline-sum-queries) or | ||||||||||||||||||
[persistent segment trees](/adv/persistent) for more details. | ||||||||||||||||||
Comment on lines
+93
to
+106
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. would be useful to tell the user why we need 2d range queries. also you don't need to split this into another section. |
||||||||||||||||||
|
||||||||||||||||||
## Implementation | ||||||||||||||||||
|
||||||||||||||||||
With a persistent segment tree. | ||||||||||||||||||
|
||||||||||||||||||
**Time Complexity:** $\mathcal{O}(N \log N)$ | ||||||||||||||||||
|
||||||||||||||||||
**Memory Complexity:** $\mathcal{O}(N \log N)$ | ||||||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||||||||||||||
|
||||||||||||||||||
```cpp | ||||||||||||||||||
#include "rainbow.h" | ||||||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. rainbow.h? |
||||||||||||||||||
#include <bits/stdc++.h> | ||||||||||||||||||
#define FOR(i, x, y) for (int i = x; i < y; i++) | ||||||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. no macros |
||||||||||||||||||
using namespace std; | ||||||||||||||||||
|
||||||||||||||||||
const int MAXN = 2e5, MAXSEG = (6e5 + 9) * 19 + 1; | ||||||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. maxseg? |
||||||||||||||||||
|
||||||||||||||||||
int cnt = 1, segtree[MAXSEG], left_c[MAXSEG], right_c[MAXSEG]; | ||||||||||||||||||
|
||||||||||||||||||
struct Segtree { | ||||||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. can you use the one from the module & codesnip it? |
||||||||||||||||||
set<int> data[MAXN + 1]; | ||||||||||||||||||
int roots[MAXN + 2]; | ||||||||||||||||||
|
||||||||||||||||||
<IncompleteSection /> | ||||||||||||||||||
void add(int x, int y) { data[x].insert(y); } | ||||||||||||||||||
|
||||||||||||||||||
void build() { | ||||||||||||||||||
FOR(i, 1, MAXN + 1) { | ||||||||||||||||||
roots[i + 1] = roots[i]; | ||||||||||||||||||
for (int j : data[i]) update(j, roots[i + 1]); | ||||||||||||||||||
} | ||||||||||||||||||
} | ||||||||||||||||||
|
||||||||||||||||||
void update(int pos, int &node, int l = 1, int r = MAXN) { | ||||||||||||||||||
segtree[cnt] = segtree[node] + 1; | ||||||||||||||||||
left_c[cnt] = left_c[node]; | ||||||||||||||||||
right_c[cnt] = right_c[node]; | ||||||||||||||||||
node = cnt++; | ||||||||||||||||||
|
||||||||||||||||||
if (l == r) return; | ||||||||||||||||||
int mid = (l + r) / 2; | ||||||||||||||||||
if (pos > mid) update(pos, right_c[node], mid + 1, r); | ||||||||||||||||||
else update(pos, left_c[node], l, mid); | ||||||||||||||||||
} | ||||||||||||||||||
|
||||||||||||||||||
int query(int l1, int r1, int l2, int r2) { | ||||||||||||||||||
if (l2 > r2) return 0; | ||||||||||||||||||
return query(l2, r2, roots[r1 + 1], 1, MAXN) - | ||||||||||||||||||
query(l2, r2, roots[l1], 1, MAXN); | ||||||||||||||||||
} | ||||||||||||||||||
int query(int a, int b, int node, int l, int r) { | ||||||||||||||||||
if (a > r || b < l) return 0; | ||||||||||||||||||
if (a <= l && b >= r) return segtree[node]; | ||||||||||||||||||
int mid = (l + r) / 2; | ||||||||||||||||||
return query(a, b, left_c[node], l, mid) + | ||||||||||||||||||
query(a, b, right_c[node], mid + 1, r); | ||||||||||||||||||
} | ||||||||||||||||||
} vertices, edges_horiz, edges_vert, rivers; | ||||||||||||||||||
|
||||||||||||||||||
int mx_r, mn_r, mx_c, mn_c; | ||||||||||||||||||
|
||||||||||||||||||
void add_river(int x, int y) { | ||||||||||||||||||
vertices.add(x, y); | ||||||||||||||||||
vertices.add(x + 1, y); | ||||||||||||||||||
vertices.add(x, y + 1); | ||||||||||||||||||
vertices.add(x + 1, y + 1); | ||||||||||||||||||
edges_horiz.add(x, y); | ||||||||||||||||||
edges_horiz.add(x + 1, y); | ||||||||||||||||||
edges_vert.add(x, y); | ||||||||||||||||||
edges_vert.add(x, y + 1); | ||||||||||||||||||
rivers.add(x, y); | ||||||||||||||||||
} | ||||||||||||||||||
|
||||||||||||||||||
void init(int R, int C, int sr, int sc, int M, char *S) { | ||||||||||||||||||
add_river(sr, sc); | ||||||||||||||||||
mx_r = mn_r = sr; | ||||||||||||||||||
mx_c = mn_c = sc; | ||||||||||||||||||
FOR(i, 0, M) { | ||||||||||||||||||
if (S[i] == 'N') sr--; | ||||||||||||||||||
if (S[i] == 'E') sc++; | ||||||||||||||||||
if (S[i] == 'S') sr++; | ||||||||||||||||||
if (S[i] == 'W') sc--; | ||||||||||||||||||
add_river(sr, sc); | ||||||||||||||||||
mx_r = max(mx_r, sr); | ||||||||||||||||||
mn_r = min(mn_r, sr); | ||||||||||||||||||
mx_c = max(mx_c, sc); | ||||||||||||||||||
mn_c = min(mn_c, sc); | ||||||||||||||||||
} | ||||||||||||||||||
vertices.build(); | ||||||||||||||||||
edges_horiz.build(); | ||||||||||||||||||
edges_vert.build(); | ||||||||||||||||||
rivers.build(); | ||||||||||||||||||
} | ||||||||||||||||||
|
||||||||||||||||||
int colour(int ar, int ac, int br, int bc) { | ||||||||||||||||||
int E = | ||||||||||||||||||
edges_horiz.query(ar + 1, br, ac, bc) + edges_vert.query(ar, br, ac + 1, bc); | ||||||||||||||||||
int V = vertices.query(ar + 1, br, ac + 1, bc); | ||||||||||||||||||
int R = rivers.query(ar, br, ac, bc); | ||||||||||||||||||
int C = (ar >= mn_r || br <= mx_r || ac >= mn_c || bc <= mx_c ? 1 : 2); | ||||||||||||||||||
return E - V + C - R; | ||||||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. use lowercase variable names |
||||||||||||||||||
} | ||||||||||||||||||
|
||||||||||||||||||
|
||||||||||||||||||
``` | ||||||||||||||||||
|
||||||||||||||||||
## Example 2 | ||||||||||||||||||
|
||||||||||||||||||
<Problems problems="e2" /> | ||||||||||||||||||
|
||||||||||||||||||
<IncompleteSection /> | ||||||||||||||||||
# Explanation | ||||||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. why is this h1 |
||||||||||||||||||
|
||||||||||||||||||
This problem involves a 2D grid. The code tracks connected region of points using heights. We will use Disjoint Set Union (DSU). As we process points by increasing height, we merge them into regions and update the answer based on their size. The logic here mirrors an application of Euler's formula for planar graphs, where we maintain | ||||||||||||||||||
boundaries (faces) as we mege points (vertices) and check their connectivity (edges). | ||||||||||||||||||
## Implementation | ||||||||||||||||||
|
||||||||||||||||||
With Euler's Formula | ||||||||||||||||||
|
||||||||||||||||||
**Time Complexity:** $\mathcal{O}(N^2 \log N)$ | ||||||||||||||||||
|
||||||||||||||||||
**Memory Complexity:** $\mathcal{O}(N^2)$ | ||||||||||||||||||
|
||||||||||||||||||
```cpp | ||||||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. ok this entire code block needs to be rewritten -- we want the code to be as readable /easy-to-understand as possible. so this means removing templates/macros |
||||||||||||||||||
int N, h[750][750]; | ||||||||||||||||||
|
@@ -35,67 +231,67 @@ int hsh(int a, int b) { return N * a + b; } | |||||||||||||||||
const int xd[4] = {1, 0, -1, 0}, yd[4] = {0, 1, 0, -1}; | ||||||||||||||||||
|
||||||||||||||||||
template <int SZ> struct DSU { | ||||||||||||||||||
int par[SZ], sz[SZ], measure[SZ]; | ||||||||||||||||||
vi comp[SZ]; | ||||||||||||||||||
DSU() { F0R(i, SZ) par[i] = i, sz[i] = 1, measure[i] = 1; } | ||||||||||||||||||
bool valid(int b, int c) { return b >= 0 && b < N && c >= 0 && c < N; } | ||||||||||||||||||
bool ok(int a, int b, int c) { | ||||||||||||||||||
if (!valid(b, c)) return 0; | ||||||||||||||||||
return par[hsh(b, c)] == a; | ||||||||||||||||||
} | ||||||||||||||||||
void addPoint(int x, pi t) { | ||||||||||||||||||
par[hsh(t.f, t.s)] = x; | ||||||||||||||||||
measure[x]++; | ||||||||||||||||||
F0R(i, 4) { | ||||||||||||||||||
if (ok(x, t.f + xd[i], t.s + yd[i])) { | ||||||||||||||||||
measure[x]--; | ||||||||||||||||||
int j = (i + 1) % 4; | ||||||||||||||||||
if (ok(x, t.f + xd[j], t.s + yd[j]) && | ||||||||||||||||||
ok(x, t.f + xd[j] + xd[i], t.s + yd[j] + yd[i])) | ||||||||||||||||||
measure[x]++; | ||||||||||||||||||
} | ||||||||||||||||||
} | ||||||||||||||||||
comp[x].pb(hsh(t.f, t.s)); | ||||||||||||||||||
} | ||||||||||||||||||
void unite(pi x, pi y) { // union-by-rank | ||||||||||||||||||
int X = hsh(x.f, x.s), Y = hsh(y.f, y.s); | ||||||||||||||||||
if (par[X] == par[Y]) return; | ||||||||||||||||||
X = par[X], Y = par[Y]; | ||||||||||||||||||
if (sz(comp[X]) < sz(comp[Y])) swap(X, Y); | ||||||||||||||||||
trav(t, comp[Y]) addPoint(X, {t / N, t % N}); | ||||||||||||||||||
comp[Y].clear(); | ||||||||||||||||||
} | ||||||||||||||||||
int par[SZ], sz[SZ], measure[SZ]; | ||||||||||||||||||
vi comp[SZ]; | ||||||||||||||||||
DSU() { F0R(i, SZ) par[i] = i, sz[i] = 1, measure[i] = 1; } | ||||||||||||||||||
bool valid(int b, int c) { return b >= 0 && b < N && c >= 0 && c < N; } | ||||||||||||||||||
SansPapyrus683 marked this conversation as resolved.
Show resolved
Hide resolved
|
||||||||||||||||||
bool ok(int a, int b, int c) { | ||||||||||||||||||
if (!valid(b, c)) return 0; | ||||||||||||||||||
return par[hsh(b, c)] == a; | ||||||||||||||||||
} | ||||||||||||||||||
void addPoint(int x, pi t) { | ||||||||||||||||||
par[hsh(t.f, t.s)] = x; | ||||||||||||||||||
measure[x]++; | ||||||||||||||||||
F0R(i, 4) { | ||||||||||||||||||
if (ok(x, t.f + xd[i], t.s + yd[i])) { | ||||||||||||||||||
measure[x]--; | ||||||||||||||||||
int j = (i + 1) % 4; | ||||||||||||||||||
if (ok(x, t.f + xd[j], t.s + yd[j]) && | ||||||||||||||||||
ok(x, t.f + xd[j] + xd[i], t.s + yd[j] + yd[i])) | ||||||||||||||||||
measure[x]++; | ||||||||||||||||||
} | ||||||||||||||||||
} | ||||||||||||||||||
comp[x].pb(hsh(t.f, t.s)); | ||||||||||||||||||
} | ||||||||||||||||||
void unite(pi x, pi y) { // union-by-rank | ||||||||||||||||||
int X = hsh(x.f, x.s), Y = hsh(y.f, y.s); | ||||||||||||||||||
if (par[X] == par[Y]) return; | ||||||||||||||||||
X = par[X], Y = par[Y]; | ||||||||||||||||||
if (sz(comp[X]) < sz(comp[Y])) swap(X, Y); | ||||||||||||||||||
trav(t, comp[Y]) addPoint(X, {t / N, t % N}); | ||||||||||||||||||
comp[Y].clear(); | ||||||||||||||||||
} | ||||||||||||||||||
}; | ||||||||||||||||||
|
||||||||||||||||||
DSU<750 * 750> D; | ||||||||||||||||||
bool ok[750][750]; | ||||||||||||||||||
|
||||||||||||||||||
void solve(int x, int y) { | ||||||||||||||||||
ok[x][y] = 1; | ||||||||||||||||||
F0R(i, 4) { | ||||||||||||||||||
int X = x + xd[i], Y = y + yd[i]; | ||||||||||||||||||
if (X < 0 || X >= N || Y < 0 || Y >= N) continue; | ||||||||||||||||||
if (!ok[X][Y]) continue; | ||||||||||||||||||
D.unite({x, y}, {X, Y}); | ||||||||||||||||||
} | ||||||||||||||||||
ok[x][y] = 1; | ||||||||||||||||||
F0R(i, 4) { | ||||||||||||||||||
int X = x + xd[i], Y = y + yd[i]; | ||||||||||||||||||
if (X < 0 || X >= N || Y < 0 || Y >= N) continue; | ||||||||||||||||||
if (!ok[X][Y]) continue; | ||||||||||||||||||
D.unite({x, y}, {X, Y}); | ||||||||||||||||||
} | ||||||||||||||||||
} | ||||||||||||||||||
|
||||||||||||||||||
int main() { | ||||||||||||||||||
setIO("valleys"); | ||||||||||||||||||
re(N); | ||||||||||||||||||
F0R(i, N) F0R(j, N) { | ||||||||||||||||||
re(h[i][j]); | ||||||||||||||||||
v.pb({h[i][j], {i, j}}); | ||||||||||||||||||
D.comp[hsh(i, j)].pb(hsh(i, j)); | ||||||||||||||||||
} | ||||||||||||||||||
sort(all(v)); | ||||||||||||||||||
F0R(i, sz(v)) { | ||||||||||||||||||
solve(v[i].s.f, v[i].s.s); | ||||||||||||||||||
pi p = v[i].s; | ||||||||||||||||||
int q = D.par[hsh(p.f, p.s)]; | ||||||||||||||||||
if (D.measure[q] == 1) ans += sz(D.comp[q]); | ||||||||||||||||||
} | ||||||||||||||||||
cout << ans; | ||||||||||||||||||
setIO("valleys"); | ||||||||||||||||||
re(N); | ||||||||||||||||||
F0R(i, N) F0R(j, N) { | ||||||||||||||||||
re(h[i][j]); | ||||||||||||||||||
v.pb({h[i][j], {i, j}}); | ||||||||||||||||||
D.comp[hsh(i, j)].pb(hsh(i, j)); | ||||||||||||||||||
} | ||||||||||||||||||
sort(all(v)); | ||||||||||||||||||
F0R(i, sz(v)) { | ||||||||||||||||||
solve(v[i].s.f, v[i].s.s); | ||||||||||||||||||
pi p = v[i].s; | ||||||||||||||||||
int q = D.par[hsh(p.f, p.s)]; | ||||||||||||||||||
if (D.measure[q] == 1) ans += sz(D.comp[q]); | ||||||||||||||||||
} | ||||||||||||||||||
cout << ans; | ||||||||||||||||||
} | ||||||||||||||||||
``` | ||||||||||||||||||
|
||||||||||||||||||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
third sentence is redundant