|
1 | | -<!--?title Convex Hull construction using Graham's Scan --> |
2 | | -# Convex Hull construction using Graham's Scan |
| 1 | +<!--?title Convex Hull construction --> |
| 2 | +# Convex Hull construction |
3 | 3 |
|
4 | 4 | In this article we will discuss the problem of constructing a convex hull from a set of points. |
5 | 5 |
|
6 | 6 | Consider $N$ points given on a plane, and the objective is to generate a convex hull, i.e. the smallest |
7 | 7 | convex polygon that contains all the given points. |
8 | 8 |
|
9 | | -The algorithm used here is **Graham's scan** (proposed in 1972 by Graham) with improvements by Andrew (1979). |
10 | | -The algorithm allows for the construction of a convex hull in $O(N \log N)$ using only comparison, |
11 | | -addition and multiplication operations. The algorithm is asymptotically optimal (as it is proven that there |
12 | | -is no algorithm asymptotically better), with the exception of a few problems where parallel or online processing |
13 | | -is involved. |
| 9 | +We will see the **Graham's scan** algorithm published in 1972 by Graham, and |
| 10 | +also the **Monotone chain** algorithm published in 1979 by Andrew. Both |
| 11 | +are $\mathcal{O}(N \log N)$, and are asymptotically optimal (as it is proven that there |
| 12 | +is no algorithm asymptotically better), with the exception of a few problems where |
| 13 | +parallel or online processing is involved. |
14 | 14 |
|
15 | | -## Description |
| 15 | +## Graham Scan Algorithm |
| 16 | +The algorithm first finds the bottom-most point $P_0$. If there are multiple points |
| 17 | +with the same Y coordinate, the one with the smaller X coordinate is considered. This |
| 18 | +step takes $\mathcal{O}(N)$ time. |
| 19 | + |
| 20 | +Next, all the other points are sorted by polar angle in counterclockwise order. |
| 21 | +If the polar angle between two points is the same, the nearest point is chosen instead. |
| 22 | + |
| 23 | +Then we iterate through each point one by one, and make sure that the current |
| 24 | +point and the two before it make a counterclockwise turn, otherwise the previous |
| 25 | +point is discarded, since it would make a non-convex shape. If the three points are collinear, |
| 26 | +you have a choice of whether to consider it part of the convex hull or not. |
| 27 | +In this implementation we are choosing not to. Checking for clockwise or anticlockwise |
| 28 | +nature can be done by checking the [orientation](./geometry/oriented-triangle-area.html). |
| 29 | + |
| 30 | +We use a stack to store the points, and once we reach the original point $P_0$, |
| 31 | +the algorithm is done and we return the stack containing all the points of the |
| 32 | +convex hull in clockwise order. |
| 33 | + |
| 34 | +### Implementation |
| 35 | + |
| 36 | +```cpp graham_scan |
| 37 | +struct pt { |
| 38 | + double x, y; |
| 39 | +}; |
| 40 | + |
| 41 | +int orientation(pt a, pt b, pt c) { |
| 42 | + double v = a.x*(b.y-c.y)+b.x*(c.y-a.y)+c.x*(a.y-b.y); |
| 43 | + if (v < 0) return -1; // clockwise |
| 44 | + if (v > 0) return +1; // counter-clockwise |
| 45 | + return 0; |
| 46 | +} |
| 47 | + |
| 48 | +bool cw(pt a, pt b, pt c) { return orientation(a, b, c) < 0; } |
| 49 | + |
| 50 | +pt p0; |
| 51 | +bool cmp(pt a, pt b) { |
| 52 | + int o = orientation(p0, a, b); |
| 53 | + if (o == 0) |
| 54 | + return (p0.x-a.x)*(p0.x-a.x) + (p0.y-a.y)*(p0.y-a.y) |
| 55 | + < (p0.x-b.x)*(p0.x-b.x) + (p0.y-b.y)*(p0.y-b.y); |
| 56 | + return o < 0; |
| 57 | +} |
| 58 | + |
| 59 | +bool cmp_p0(pt a, pt b) { |
| 60 | + return a.y < b.y || (a.y == b.y && a.x < b.x); |
| 61 | +} |
| 62 | + |
| 63 | +void convex_hull(vector<pt>& a) { |
| 64 | + p0 = *min_element(a.begin(), a.end(), cmp_p0); |
| 65 | + sort(a.begin(), a.end(), &cmp); |
| 66 | + |
| 67 | + vector<pt> st; |
| 68 | + for (int i = 0; i < (int)a.size(); i++) { |
| 69 | + while (st.size() > 1 && !cw(st[st.size()-2], st.back(), a[i])) |
| 70 | + st.pop_back(); |
| 71 | + st.push_back(a[i]); |
| 72 | + } |
| 73 | + |
| 74 | + a = st; |
| 75 | +} |
| 76 | +``` |
| 77 | + |
| 78 | +## Monotone chain Algorithm |
16 | 79 | The algorithm first finds the leftmost and rightmost points A and B. In the event multiple such points exist, |
17 | 80 | the lowest among the left (lowest Y-coordinate) is taken as A, and the highest among the right (highest Y-coordinate) |
18 | 81 | is taken as B. Clearly, A and B must both belong to the convex hull as they are the farthest away and they cannot be contained |
@@ -40,11 +103,11 @@ orientation instead of a clockwise orientation. Thus, if the angle made by the l |
40 | 103 | with the line connecting the last point in the lower convex hull and the current point is not counterclockwise, we remove the most recent point added to the lower convex hull as the current point will be able to contain |
41 | 104 | the previous point once added to the hull. |
42 | 105 |
|
43 | | -The final convex hull is obtained from the union of the upper and lower convex hull, and the implementation is as follows. |
| 106 | +The final convex hull is obtained from the union of the upper and lower convex hull, forming a clockwise hull, and the implementation is as follows. |
44 | 107 |
|
45 | | -## Implementation |
| 108 | +### Implementation |
46 | 109 |
|
47 | | -```cpp grahams_scan |
| 110 | +```cpp monotone_chain |
48 | 111 | struct pt { |
49 | 112 | double x, y; |
50 | 113 | }; |
|
0 commit comments