컨벑슀 헐 (Convex Hull)

Convex Hull μ΄λž€?

 

2차원 평면에 μ’Œν‘œλ“€μ΄ μ£Όμ–΄μ‘Œμ„λ•Œ κ°€μž₯ λ°”κΉ₯μͺ½μ˜ μ’Œν‘œλ“€λ§Œ μ—°κ²°ν•˜μ—¬ λ‹€κ°ν˜•μ„ λ§Œλ“œλŠ” μ•Œκ³ λ¦¬μ¦˜

κ²°κ³Όμ μœΌλ‘œλŠ” 컨벑슀 헐을 κ΅¬μ„±ν•˜λŠ” μ λ“€μ˜ μ’Œν‘œλ₯Ό 얻을 수 μžˆλ‹€.

λͺ¨λ“  μ’Œν‘œλ“€μ€ ꡬ해진 경계선 μ•ˆμ— μ‘΄μž¬ν•œλ‹€. 그렇기에 점듀이 μ°¨μ§€ν•˜λŠ” μ΅œμ†Œ μ˜μ—­μ„ ꡬ할 수 μžˆλ‹€.

 

 

Graham Scan Algorithm

 

- λ¨Όμ € 점듀을 yμ’Œν‘œ κΈ°μ€€, κ°™μœΌλ©΄ xμ’Œν‘œ κΈ°μ€€μœΌλ‘œ μ •λ ¬ν•œλ‹€. (μ˜€λ¦„μ°¨μˆœ) -> μ–΄λ””μ—μ„œ μ‹œμž‘(κ°€μž₯ μ•„λž˜)ν•˜λŠ”μ§€

- κ°€μž₯ μ•„λž˜μ— μžˆλŠ” 점을 κΈ°μ€€μœΌλ‘œ, λ‚˜λ¨Έμ§€ 점듀을 각도 κΈ°μ€€μœΌλ‘œ μ •λ ¬ν•œλ‹€.

  (κ°λ„λŠ” κΈ°μ€€μ μ—μ„œ λ°˜μ‹œκ³„λ°©ν–₯(각도 λ†’μŒ)인지 확인. CCW(Counter Clock Wise) μ‚¬μš©)

    CCW νŒλ³„: p->q->r의 νšŒμ „ μ•Œκ³ μ‹Άμ„λ•Œ (q.x - p.x) * (r.y - p.y) - (q.y - p.y) * (r.x - p.x)

    => κ²°κ³Όκ°€ 음수면 μ‹œκ³„λ°©ν–₯, μ–‘μˆ˜λ©΄ λ°˜μ‹œκ³„λ°©ν–₯. μ ˆλŒ“κ°’μ€ κΊΎμ΄λŠ” 정도 λ‚˜νƒ€λƒ„.

 

- 기쀀점뢀터 μˆœμ„œλŒ€λ‘œ 점을 λ³΄λ©΄μ„œ μŠ€νƒμ— λ„£λ˜, μŠ€νƒμ˜ μƒμœ„ 두 점과 ν˜„μž¬ 점이 μ‹œκ³„ λ°©ν–₯을 이루면 pop ν•œλ‹€.

- 이 과정을 λ°˜λ³΅ν•˜μ—¬, λ°˜μ‹œκ³„ λ°©ν–₯(CCW)만 μœ μ§€ν•˜λ„λ‘ ν•œλ‹€.

- λͺ¨λ“  점을 ν™•μΈν–ˆμ„λ•Œ μŠ€νƒμ— λ‚¨μ•„μžˆλŠ” 값이 μ»¨λ²‘μŠ€ν—μ΄ λœλ‹€.

 

 

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
import java.util.*;
 
// μ μ„ ν‘œν˜„ν•˜λŠ” ν΄λž˜μŠ€
class Point {
    int x, y;
 
    Point(int x, int y) {
        this.x = x;
        this.y = y;
    }
 
    // λ‘ μ μ˜ λ°©ν–₯을 κ³„μ‚°ν•˜λŠ” λ©”μ„œλ“œ (ꡐ차 κ³±)
    static int crossProduct(Point p, Point q, Point r) {
        return (q.x - p.x) * (r.y - p.y) - (q.y - p.y) * (r.x - p.x);
    }
}
 
public class ConvexHull {
 
    // κ·ΈλΌν•¨ μŠ€μΊ” μ•Œκ³ λ¦¬μ¦˜
    public static List<Point> grahamScan(List<Point> points) {
        if (points.size() < 3) {
            return points;
        }
 
        // 기쀀점 μ°ΎκΈ°
        points.sort((p1, p2) -> (p1.y == p2.y) ? Integer.compare(p1.x, p2.x) : Integer.compare(p1.y, p2.y));
        Point start = points.remove(0);
 
        // 각도기쀀 μ •λ ¬
        points.sort((p1, p2) -> {
            int cp = Point.crossProduct(start, p1, p2);
            if (cp == 0) {
                return Integer.compare(distance(start, p1), distance(start, p2));
            }
            return cp > 0 ? -1 : 1;
        });
 
        // CCW νŒλ³„λ‘œ μ»¨λ²‘μŠ€ν— κ΅¬μ„±ν•˜λŠ”μ§€ 확인
        Stack<Point> stack = new Stack<>();
        stack.push(start);
      stack.push(points.get(0));
 
        for (int i = 1; i < points.size(); i++) {
            while (stack.size() > 1 && Point.crossProduct(stack.get(stack.size() - 2), stack.peek(), points.get(i)) <= 0) {
                stack.pop();
            }
            stack.push(points.get(i));
        }
 
        // μŠ€νƒμ— λ‚¨μ€ μ λ“€μ΄ μ»¨λ²‘슀 ν—μ„ κ΅¬μ„±ν•˜λŠ” μ λ“€
        return new ArrayList<>(stack);
    }
 
    // 두 점 κ°„μ˜ 거리
    public static int distance(Point p1, Point p2) {
        return (p1.x - p2.x) * (p1.x - p2.x) + (p1.y - p2.y) * (p1.y - p2.y);
    }
 
    // μ΅œμ’… 좜λ ₯
    public static void printConvexHull(List<Point> convexHull) {
        for (Point p : convexHull) {
            System.out.println("(" + p.x + ", " + p.y + ")");
        }
    }
 
    public static void main(String[] args) {
        List<Point> points = new ArrayList<>();
        points.add(new Point(00));
        points.add(new Point(11));
        points.add(new Point(22));
        points.add(new Point(44));
        points.add(new Point(04));
        points.add(new Point(13));
        points.add(new Point(30));
 
        List<Point> convexHull = grahamScan(points);
        System.out.println("컨벑슀 ν—μ„ κ΅¬μ„±ν•˜λŠ” μ λ“€:");
        printConvexHull(convexHull);
    }
}
 
cs