백준 No.17387 [선분 교차 2]
본문 바로가기
Algorithm (C++ based)/BOJ

백준 No.17387 [선분 교차 2]

by 조훈이 2021. 6. 29.

Baekjoon Online Judge No.17387 [선분 교차 2]


 문제 

 

17387번: 선분 교차 2

첫째 줄에 L1의 양 끝 점 x1, y1, x2, y2가, 둘째 줄에 L2의 양 끝 점 x3, y3, x4, y4가 주어진다.

www.acmicpc.net


 설명 

  이전 17386번: 선분 교차 1 (acmicpc.net) 문제에서 조건이 더 추가가 된 문제이다. [선분 교차 1] 문제에선 세 점이 한 직선상에 있는 경우가 없었지만, 이번 문제에선 세 점이 한 직선상에 있는 경우가 있기에 이 조건까지 처리를 해야 한다. 이전에 올린 [선분 교차 1] 게시물에서 더 추가해야 하는 조건을 설명 해 보고자 한다.

 

  백준 No.17386 [선분 교차 1] 설명 Link2021.06.28 - [C++ Algorithm/Math] - 백준 No.17386 [선분 교차 1]

 

백준 No.17386 [선분 교차 1]

Baekjoon Online Judge No.17386 [선분 교차 1]  문제 17386번: 선분 교차 1 첫째 줄에 L1의 양 끝 점 x1, y1, x2, y2가, 둘째 줄에 L2의 양 끝 점 x3, y3, x4, y4가 주어진다. 세 점이 일직선 위에 있는 경우..

johoonday.tistory.com


  [선분 교차 1] 에선 두 선분의 내부끼리 교차하는 경우만을 고려하였다. 하지만 이번 문제에선 세 점이 한 직선상에 있는 경우와 네 점 모두 한 직선상에 있는 경우를 고려해야 한다.

 

<세 점이 한 직선상에 있는 경우>

  세 점이 한 직선상에 있는 경우는 위 세 가지 경우로 나뉜다. 

 

  Case 1) CCW(A, B, C) * CCW(A, B, D) < 0   &&   CCW(C, D, A) * CCW(C, D, B) == 0
  Case 2) CCW(A, B, C) * CCW(A, B, D) == 0   &&   CCW(C, D, A) * CCW(C, D, B) == 0
  Case 3) CCW(A, B, C) * CCW(A, B, D) > 0   &&   CCW(C, D, A) * CCW(C, D, B) == 0

 

  Case 1, Case 2 는 교차 하는 경우이며 Case 3 은 교차하지 않는 경우이다. 위 세 Case 들로 아래와 같은 조건을 도출할 수 있다.

 

CCW(A, B, C) * CCW(A, B, D) <= 0   &&   CCW(C, D, A) * CCW(C, D, B) <= 0

 

  이 조건을 확인 한다면, 두 선분의 내부끼리만 교차하는 경우세 점이 한 직선상에 있는 경우에 교차 여부를 확인할 수 있다.

 


<네 점이 한 직선상에 있는 경우>

  네 점이 한 직선상에 있는 경우는, 점들간의 거리로 확인을 하였다. 위와 같이 두 케이스만 고려하면 된다.

 

  Case 1) A--B 의 거리보다 A--C,   A--D 의 거리가 더 멀어서 교차하지 않는 경우 -> 교차하지 않는다.
  Case 2) A--B 의 거리보다 A--C 혹은 A--D 의 거리가 더 짧은 경우 -> 교차한다.

 

  위 경우는 점 A 와 다른 세 점의 거리에 대해서 체크를 한 경우들이고 위와 같은 경우들을 점 B와 다른 세 점에 대해서만 한번 더 체크하면 된다.


 Code 

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
#include <iostream>
 
using namespace std;
 
typedef long long LL;
 
struct coordinate {
    LL x;
    LL y;
 
    void read() { cin >> x >> y; }
};
 
// A---B---C 순서대로 한 직선에 나열이 되어 있는지 확인하는 함수
bool isLined(coordinate A, coordinate B, coordinate C) {
    if (A.x < B.x) {
        return B.x < C.x;
    }
    else if (B.x < A.x) {
        return C.x < B.x;
    }
    else {
        if (A.y < B.y) {
            return B.y < C.y;
        }
        else if (B.y < A.y) {
            return C.y < B.y;
        }
    }
}
 
int CCW(coordinate A, coordinate B, coordinate C) {
    // temp 에 대한 연산을 나누는 이유 : 연산 과정에서 Overflow가 발생할 수 있으므로
    LL temp = (A.x * B.y) + (B.x * C.y) + (C.x * A.y);
    temp -= (A.x * C.y) + (B.x * A.y) + (C.x * B.y);
 
    // CCW의 값이 양수인지, 0 인지, 음수인지만 알면 되므로 아래와 같이 return 을 하였다.
    if (temp > 0return 1;
    else if (!temp) return 0;
    else return -1;
}
 
bool isOverlapped(coordinate A, coordinate B, coordinate C, coordinate D) {
    int ans1 = CCW(A, B, C) * CCW(A, B, D); // 선분AB를 기준으로 점 C, 점 D 를 체크하는 부분
    int ans2 = CCW(C, D, A) * CCW(C, D, B); // 선분CD를 기준으로 점 A, 점 B 를 체크하는 부분
 
    if (!ans1 && !ans2) {    // 네 점이 모두 같은 선 상에 있을 때
                            // A--B 의 거리보다 A--C, A--D의 거리가 더 멀거나
                            // B--A 의 거리보다 B--C, B--D의 거리가 더 멀면 교점이 없는 경우이므로 false를 return
        if ((isLined(A, B, C) && isLined(A, B, D)) || (isLined(B, A, C) && isLined(B, A, D))) return false;
        else return true;    // 그렇지 않은 경우는 겹치는 부분이 존재하는 경우이므로 true를 return
    }
    else return (ans1 <= 0&& (ans2 <= 0); // 위에서 설명이 된 조건에 부합하면 1, 부합하지 않으면 0을 return
}
 
int main() {
    coordinate A, B, C, D;
 
    A.read(); B.read();
    C.read(); D.read();
 
    if (isOverlapped(A, B, C, D)) cout << "1";
    else cout << "0";
}
cs
728x90

'Algorithm (C++ based) > BOJ' 카테고리의 다른 글

백준 No.1328 [고층 빌딩]  (0) 2021.07.12
백준 No.1937 [욕심쟁이 판다]  (0) 2021.07.11
백준 No.17386 [선분 교차 1]  (0) 2021.06.28
백준 No.7579 [앱]  (0) 2021.02.22
백준 No.11404 [플로이드]  (0) 2021.02.20

댓글