Skyline Problem
2020-1νκΈ°, λνμμ βμκ³ λ¦¬μ¦β μμ μ λ£κ³ 곡λΆν λ°λ₯Ό μ 리ν κΈμ λλ€. μ§μ μ μΈμ λ νμμ λλ€ :)
λ°±μ€ 1933λ²: μ€μΉ΄μ΄λΌμΈ λ¬Έμ λ₯Ό λ€λ£¨λ ν¬μ€νΈμ λλ€ π
Given n rectangular buildings in a 2-dimensional city, computes the skyline of these buildings, eliminating hidden lines. The main task is to view buildings from a side and remove all sections that are not visible.
All buildings share common bottom and every building is represented by triplet (left, ht, right)
- βleftβ: is x coordinated of left side (or wall).
- βrightβ: is x coordinate of right side
- βhtβ: is height of building.
A skyline is a collection of rectangular strips. A rectangular strip is represented as a pair (left, ht) where left is x coordinate of left side of strip and ht is height of strip.
<Skyline Problem>μ μ¬λ¬ κ°μ μ§μ¬κ°ν λΉλ©μμ κ·Έλ€μ ν
λλ¦¬μΈ skylineμ κ³μ°νλ λ¬Έμ μ΄λ€. μΆλ ₯ νμμ 보면 μ μ μλ―μ΄ λμ΄(ht)κ° λ³ν λμ x μ§μ λ§ (x, ht)
λ‘ μΆλ ₯ν΄μ£Όλ©΄ λλ€. <Brute Force>μ <Divide and Conquery>λ‘ λ¬Έμ λ₯Ό ν΄κ²°ν΄λ³΄μ!
Brute Force
1. Mark key points for each given building.
[left, ht, right]
νμμ κ° λΉλ©μ [left, ht], [right, 0]
νμμΌλ‘ λ°κΏμ€λ€.
2. For each marked key point, if there exist heighter key points overlap it, then change its y
as the height of tallest overlapping building.
μΌμͺ½μμ μ€λ₯Έμͺ½ λ°©ν₯μΌλ‘ μ²μ²ν λ°λΌκ°λ³΄μ!
λ¨Όμ μ΄λ‘μ λΉλ©μ [left, ht]
μ μ λΉ¨κ°μ λΉλ©μ overlapping λκΈ° λλ¬Έμ y
κ°μ κ°±μ νλ€. μ΄λ, [left, ht]
κ° μ체λ₯Ό κ°±μ νλκ² μλλΌ κ°±μ λ [left, ht_new]
λ₯Ό result array vector<point> ret
μ λ£μ΄λλ©΄ λλ€.
μ΄ λ°©λ²μ κ³μνλ©΄β¦
λͺ¨λ key pointλ₯Ό λ€ λμλ€λ©΄, vector<point> ret
μμ y κ°μ΄ μ€λ³΅λλ μ λ€μ μ κ±°νλ©΄ λλ€.
κ° key pointμ overlap λλ tallest buildingμ μ°ΎκΈ° μν΄ building
λ°°μ΄μ μννλ€: $O(n)$. λ°λΌμ $n$κ° key pointλ₯Ό μ²λ¦¬νλλ° $O(n)$ λ§νΌμ μ°μ°μ΄ νμνλ―λ‘, Brute Force λ°©μμ $O(n^2)$μ μκ°λ³΅μ‘λλ₯Ό κ°λλ€.
Brute Force νμ΄
#include <bits/stdc++.h>
using namespace std;
#define MAX 100005
typedef pair<int, int> Coord;
typedef pair<pair<int, int>, int> Building;
vector<Building> blding;
vector<Coord> key_points; // collection of key points
vector<Coord> ret;
int main() {
int N;
scanf("%d", &N);
for (int i = 0; i < N; i++) {
int l, h, r;
scanf("%d %d %d", &l, &h, &r);
blding.push_back({ { l, r }, h });
key_points.push_back({ l, h });
key_points.push_back({ r, 0 });
}
sort(key_points.begin(), key_points.end());
// process key points!
for (Coord &point : key_points) {
int x = point.first, y = point.second;
int max_h = y;
for (Building &building : blding) {
int b_left = building.first.first, b_right = building.first.second;
if (b_left > x || b_right <= x) continue;
max_h = max(max_h, building.second);
}
ret.push_back({x, max_h});
}
// show intermediate result
for (int i = 0; i < ret.size(); i++) {
printf("(%d %d) ", ret[i].first, ret[i].second);
}
printf("\n");
// process redundant key points
// how? compare with behind
vector<Coord> final_ret;
final_ret.push_back(ret[0]);
for (int i = 1; i < ret.size(); i++) {
int prev_h = ret[i - 1].second;
int curr_h = ret[i].second;
if (prev_h != curr_h) {
final_ret.push_back(ret[i]);
}
}
// show final result
for (int i = 0; i < final_ret.size(); i++) {
printf("%d %d ", final_ret[i].first, final_ret[i].second);
}
return 0;
}
λΉμ°ν μκ°μ΄κ³Όκ° λλ μ μΆνμ§ λ§ κ²!
Divide and Conquer (feat. Merge Sort)
μ΄λ²μλ λ€λ₯Έ λ°©λ²μΌλ‘ μ΄ λ¬Έμ λ₯Ό νμ΄λ³΄μ. μ λͺ©μ <Divide-and-Conquery>μ§λ§ ν΅μ¬μ μΈ μμ΄λμ΄λ <Merge Sort>λ€.
μΌλ¨ <Merge Sort>μ λ°©μλλ‘ λ¬Έμ λ₯Ό μ λ°μ© λλμ΄ ν΄κ²°ν ν, κ·Έ κ²°κ³Όλ₯Ό <Merge>ν μμ μ΄λ€. λ¨Όμ μ λ°μ© λλλ κ²λΆν° μ΄ν΄λ³΄λ©΄,
vector<Coord> skyline(vector<Building> buildings) {
if (buildings.size() == 0) {
return vector<Coord>();
} else if (buildings.size() == 1) {
int l = buildings[0].first.first, r = buildings[0].first.second, h = buildings[0].second;
return vector<Coord>({ {l, h}, {r, 0} });
} else {
int mid = buildings.size() / 2;
vector<Coord> left_side = skyline(vector<Building>(buildings.begin(), buildings.begin() + mid));
vector<Coord> right_side = skyline(vector<Building>(buildings.begin() + mid, buildings.end()));
return merge(left_side, right_side);
}
}
μ
λ ₯λ°μ vector<Building>
μ μ λ°μ© λλμ΄ κ²°κ³Όλ₯Ό λμΆν ν merge()
λ₯Ό ν΅ν΄ ν©μΉλ€. μ, κ·ΈλΌ μ΄λ»κ² 2κ°μ vector<Coord>
λ₯Ό μ μ ν ν©μΉλλκ° μ€μν΄μ‘λ€!! π
2κ°μ skyline λ°°μ΄μ mergeνλ λ°©λ²μ μλμ κ°λ€.
1. Letβs compare key points of skylines starting from the leftmost end.
2. For two key points of two skylines, choose the one skyline having key point with lesser x
value.
3. If y
value of chosen key point is less than the last seen height of other skyline. then update key pointβs y
to the last seen height of other skyilne.
4. Proceed to next key point of the chosen skyline.
5. Repeat [2-4] steps until both the skylines are completed.
6. Remove the redundant key points.
μ! κ·ΈλΌ μμ μκ³ λ¦¬μ¦μ λ¨κ³λ³λ‘ μνν΄λ³΄μ.
μμ°!! λλΌμ΄ λ°©λ²μΌλ‘ λ skylineμ merge νλ€!! π² μ½λλ‘ μμ±νλ©΄ μλμ κ°λ€.
vector<Coord> merge(vector<Coord> left_side, vector<Coord> right_side) {
int i = 0, j = 0;
int last_h1 = -1, last_h2 = -1;
vector<Coord> ret;
while (i < left_side.size() && j < right_side.size()) {
Coord p1 = left_side[i], p2 = right_side[j];
if (p1.first < p2.first) {
ret.push_back({p1.first, max(p1.second, last_h2)});
last_h1 = p1.second;
i += 1;
} else if (p1.first > p2.first) {
ret.push_back({p2.first, max(p2.second, last_h1)});
last_h2 = p2.second;
j += 1;
} else {
// see later
}
}
for (; i < left_side.size(); i++) {
ret.push_back(left_side[i]);
}
for (; j < right_side.size(); j++) {
ret.push_back(right_side[j]);
}
// process redundants
vector<Coord> final_ret;
final_ret.push_back(ret[0]);
for (int i = 1; i < ret.size(); i++) {
int prev_h = ret[i - 1].second;
int curr_h = ret[i].second;
if (prev_h != curr_h) {
final_ret.push_back(ret[i]);
}
}
return final_ret;
}
κ·Έλ¬λ μμ merge μκ³ λ¦¬μ¦μμ μ°λ¦¬λ λ key pointμ x κ°μ΄ κ°μ κ²½μ°λ₯Ό λ€λ£¨μ§ μμλ€!
μ΄ κ²½μ°λ μλμ κ°μ΄ ν΄κ²°νλ€.
If x
values of both key points are same, then choose the one with higher y
value and advance key points for both skylines.
κ·Έλμ μμ μ½λμμ ν΄λΉ λΆλΆμ μ±μ°λ©΄ μλμ κ°λ€.
if (p1.first < p2.first) {
ret.push_back({p1.first, max(p1.second, last_h2)});
last_h1 = p1.second;
i += 1;
} else if (p1.first > p2.first) {
ret.push_back({p2.first, max(p2.second, last_h1)});
last_h2 = p2.second;
j += 1;
} else {
ret.push_back({p1.first, max(p1.second, p2.second)});
last_h1 = p1.second;
last_h2 = p2.second;
i += 1;
j += 1;
}
μ΄κ²μΌλ‘ <Skyline Problem>μ λν΄ μ΄ν΄λ³΄μλ€. ν κ°μ§ νμ΄λ²μ΄ λ μλ€κ³ νλλ°, <μ°μ μμ ν>λ₯Ό μ΄μ©νλ λ°©μμ΄λ€. μ΄ λ μμ λμ€μ μκ°μ΄ λλ©΄ μ 리νλλ‘ νκ² λ€ π