WonYong-Jang / algorithm

0 stars 0 forks source link

기하 ( ccw / 선분 교차 / 볼록 껍질 / rotating 캘리퍼스 / Line sweeping / Convex hull trick ) #32

Open WonYong-Jang opened 5 years ago

WonYong-Jang commented 5 years ago

ccw

public static int ccw(Point a, Point b, Point c)
{
    long op = ( (a.dx*b.dy)+(b.dx*c.dy)+(c.dx*a.dy) - (a.dy*b.dx) + (b.dy*c.dx)+(c.dy*a.dx) );
    if(op > 0) return 1; // 반시계 방향
    else if(op < 0) return -1; // 시계 방향
    else return 0; // 세점이 평행
}

다각형의 내부 외부 판별

스크린샷 2019-06-29 오후 2 03 24

다각형의 내부 외부 판별 구현

1) 점 B의 y좌표가 두 선분 꼭지점의 y좌표 사이에 있다. 2) 점 B를 지나는 수평선과 선분 사이의 교점의 x좌표가 점 B의 좌표보다 크다.

=> 조건1을 만족하면 점 B를 지나는 수평 직선과 선분사이에 반드시 교점이 존재. 이때 오른쪽 
반직선과의 교점만 세야 하므로 조건 2를 추가로 만족해야 반직선과 선분 사이의 교점 존재 여부를
올바르게 판별 가능!

<img width="600" alt="스크린샷 2019-06-29 오후 2 19 02" src="https://user-images.githubusercontent.com/26623547/60380017-e7f72e80-9a78-11e9-9703-93c9a81f7bc3.png">

<img width="600" alt="스크린샷 2019-06-29 오후 2 19 11" src="https://user-images.githubusercontent.com/26623547/60380018-f2192d00-9a78-11e9-8d8d-4c9616c6709c.png">

public static boolean isCross(long tx, long ty) { int crossCnt = 0; long mindy =0, maxdy =0; for(int i=0; i< N; i++) { Point p1 = p[i]; Point p2 = p[(i+1) % N];

    mindy = min(p1.dy, p2.dy);
    maxdy = max(p1.dy, p2.dy);

    if(mindy <= ty && maxdy >= ty) // 선분 y 좌표 사이에 있는지 확인 
    {

        long tmp = p2.dy - p1.dy; // 분모가 0 일 경우 제외 
        if(tmp == 0) continue;
        // 점과 직선사이의 수선의 발 좌표 공식
        long target = (ty - p1.dy)*(p2.dx - p1.dx) / (p2.dy - p1.dy) + p1.dx;

        if(tx < target) crossCnt++;
    }
}
if(crossCnt % 2 != 0) return true;
else return false;

}



참고 링크 : https://bowbowbow.tistory.com/24

# 교차 판별

<img width="500" alt="스크린샷 2019-06-15 오후 1 28 19" src="https://user-images.githubusercontent.com/26623547/59546958-8eb7d700-8f71-11e9-85ca-7f2c9f1b772e.png">

<img width="775" alt="스크린샷 2019-06-15 오후 1 28 27" src="https://user-images.githubusercontent.com/26623547/59546959-98413f00-8f71-11e9-99f9-800d3195d9ee.png">

<img width="819" alt="스크린샷 2019-06-15 오후 1 28 45" src="https://user-images.githubusercontent.com/26623547/59546963-a0997a00-8f71-11e9-92e9-18f65ed2187b.png">

출처 : https://jason9319.tistory.com/358
WonYong-Jang commented 5 years ago

볼록 껍질

public class Main {

    static int N;
    static Point[] p = new Point[100005];
    static Point p0;
    static Stack<Integer> stack = new Stack<>();
    public static void main(String[] args) throws IOException {
        // TODO Auto-generated method stub
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        StringTokenizer st = new StringTokenizer(br.readLine());
        N = Integer.parseInt(st.nextToken());
        int dx =0, dy =0;
        p0 = new Point(40001,40001);
        for(int i=1; i<= N; i++)
        {
            st = new StringTokenizer(br.readLine());
            dx = Integer.parseInt(st.nextToken());
            dy = Integer.parseInt(st.nextToken());
            p[i] = new Point(dx, dy);
            if(p0.dy > p[i].dy) {
                p0.dx = p[i].dx;
                p0.dy = p[i].dy;
            }
            if(p0.dy == p[i].dy && p0.dx > p[i].dx) {
                p0.dx = p[i].dx;
                p0.dy = p[i].dy;
            }
        }
        Arrays.sort(p, 1, N+1, new mySort()); // 각 정렬 ( 반시계 방향 기준 ) 

        stack.add(1);
        stack.add(2);
        int next = 3, second =0, first =0, op =0;
        while(next <= N)
        {
            while(stack.size() >= 2)
            {
                second = stack.pop();
                first = stack.peek();
                op = ccw(p[first], p[second], p[next]);
                if(op > 0) {
                    stack.add(second);
                    break;
                }
            }
            stack.push(next++);
        }
        System.out.println(stack.size());
    }
    public static int ccw(Point a, Point b, Point c)
    {
        long tmp = ((long)(a.dx*b.dy) + (long)(b.dx*c.dy) + (long)(c.dx*a.dy)) - ((long)(a.dy*b.dx) + (long)(b.dy*c.dx) + (long)(c.dy*a.dx));
        if(tmp > 0) return 1;
        else if(tmp < 0) return -1;
        else return 0;
    }
    public static long dis(Point a, Point b)
    {
        return (long)(a.dx-b.dx)*(a.dx-b.dx) + (long)(a.dy-b.dy)*(a.dy-b.dy);   
    }
    static class mySort implements Comparator<Point> {
        @Override
        public int compare(Point a, Point b) {
            int t = ccw(p0, a, b);
            if(t == 0)
            {
                long d1 = dis(p0,a);
                long d2 = dis(p0,b);
                if(d1 < d2) return -1;
                else if(d1 > d2) return 1;
                else return 0;
            }
            return t > 0 ? -1 : 1;
        }
    }
    static class Point {
        int dx, dy;
        Point(int a, int b) { 
            dx=a; dy=b;
        }
    }
}
WonYong-Jang commented 5 years ago

Convex Hull Trick

관련 문제 : 나무 자르기 (백준 13263 )

WonYong-Jang commented 5 years ago

Line sweeping

2170 선 긋기

5419 북서풍

2261 , 5620가장 가까운 두점 ( 분할정복, line sweeping 둘다 가능)

링크 : http://m.blog.daum.net/rhaoslikesan/284?categoryId=30

7574 개구리

WonYong-Jang commented 5 years ago

Plane sweeping

관련 링크 : https://codedoc.tistory.com/421