Plite
전자오락 공방
Plite
전체 방문자
오늘
어제
  • 분류 전체보기 (274)
    • 프로젝트 (18)
      • 완성 프로젝트 (3)
      • 프로젝트 진행 내역 (15)
    • 공부 및 정리 (241)
      • 백준 코드 (222)
      • C++ (8)
      • DirectX (2)
      • Unreal Engine (6)
      • 프로그래밍 패턴 (3)
    • 기타 (12)
      • 기타 주저리 (10)
    • 게임과 취미 (1)
    • 대문 (1)

블로그 메뉴

  • 홈
  • 프로젝트
  • 취미, 일상
  • 백준 프로필

공지사항

  • [Read Me]
  • 제 블로그에 방문하신 것을 환영합니다.

인기 글

태그

  • 정렬
  • C++
  • 브루트포스
  • 이분탐색
  • 세그먼트 트리
  • 큐
  • 트라이
  • 백트래킹
  • 분할정복
  • 백준
  • SCC
  • 유니온 파인드
  • 구현
  • 스택
  • KMP
  • 투포인터
  • 그래프
  • 위상 정렬
  • UC++
  • 트리
  • LCA
  • 누적합
  • 동적계획법
  • 최소 스패닝 트리
  • 조합론
  • 수학
  • 정수론
  • 문자열
  • 기하
  • 우선순위큐

최근 댓글

최근 글

티스토리

hELLO · Designed By 정상우.
Plite
공부 및 정리/백준 코드

[C++]백준 - 20149번 문제

[C++]백준 - 20149번 문제
공부 및 정리/백준 코드

[C++]백준 - 20149번 문제

2021. 11. 9. 18:04

20149번: 선분 교차 3 (acmicpc.net)

 

20149번: 선분 교차 3

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

www.acmicpc.net

 

20149번 : 선분 교차 3


2차원 좌표 평면 위의 두 선분 L1, L2가 주어졌을 때, 두 선분이 교차하는지 아닌지 구해보자. 한 선분의 끝 점이 다른 선분이나 끝 점 위에 있는 것도 교차하는 것이다.

L1의 양 끝 점은 (x1, y1), (x2, y2), L2의 양 끝 점은 (x3, y3), (x4, y4)이다.

 

입력


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

 

  • -1,000,000 ≤ x1, y1, x2, y2, x3, y3, x4, y4 ≤ 1,000,000
  • x1, y1, x2, y2, x3, y3, x4, y4는 정수

 

 

출력


L1과 L2가 교차하면 첫째 줄에 1, 아니면 0을 출력한다.

두 선분이 한 점에서 교차하는 경우 둘째 줄에 교차하는 점의 x좌표와 y좌표를 공백으로 구분해 출력한다. 한 점에서 교차하지 않는 경우에는 둘째 줄을 출력하지 않는다.

좌표의 절대/상대 오차는 10-9까지 허용한다.

 

 

 


 

생각해 볼 점


교차판정은 17387에서 사용한 코드를 그대로 쓸 것입니다.

 

교차점은 Double을 이용해 계산을 할 것인데, 주의해야할 사항이 있습니다.

 

y = ax + b (a = 기울기)

의 공식을 써서 계산할 때, 

 

double a = 기울기 값;

 

과 같은 형태로 기울기를 변수에 저장해서 다시 계산해서는 안됩니다.

 

부동 소수점 오차로 인해서 정말 작은 단위의 오차도 곱해지고 더해지면서 큰 오차로 변하게 됩니다.

 

절대 변수를 이용해서 중간 결과를 저장하지 마세요!

 

그러므로, 저희는 정수 형태의 변수들만 이용해서 계산할 것입니다.

 

물론, 결과값은 소수점 형태로 변하겠지만, 한번에 계산하여 오차를 최대한 줄일 것입니다.

 

두 직선의 방정식은 다음과 같이 나타낼 수 있습니다.

 

Y - y1 =  a1(X - x1)

Y - y3 = a2(X - x3) 

 

이 방정식 두개를 이용해 X의 값을 구하면

 

(a1 - a2)X = y3 - y1 + a1 * x1 - a2 * x3

X = (y3 - y1 + a1x1 - a2x3) / (a1 - a2)
X = {(y3 - y1)(x2 - x1)(x4 - x3) + x1(y2 - y1)(x4 - x3) - x3(y4 - y3)(x2 - x1)} / {(y2 - y1)(x4 - x3) - (y4 - y3)(x2 - x1)}

 

위와 같이 정리됩니다.

이 식을 다시 방정식에 대입하면 Y의 값의 식 또한 도출할 수 있습니다.

 

이를 그대로 코드에 적어서 답을 도출하면 정답입니다.

 

코드


#include <iostream>
using namespace std;
typedef long long ll;
typedef pair<ll, ll> Point;
#define swap(A, B) {Point temp; temp = A; A = B; B = temp;}


//두 직선 방정식을 구한 후, 교차점을 구함
void get_point(Point P1, Point P2, Point P3, Point P4)
{
    //y - y1 = a1(x - x1)
    //y - y3 = a2(x - x3)
    //y1 - y3 = a1x1 - a1x + a2x - a2x3
    //(a1 - a2)x = y3 - y1 + a1x1 - a2x3
    //x = (y3 - y1 + a1x1 - a2x3) / (a1 - a2) - > 정리하면
    //x = {(y3 - y1)(x2 - x1)(x4 - x3) + x1(y2 - y1)(x4 - x3) - x3(y4 - y3)(x2 - x1)} / {(y2 - y1)(x4 - x3) - (y4 - y3)(x2 - x1)}

    //y = (a1y3 - a1a2x3 + a1a2x1 - a2y1)/ (a1 - a2) -> 정리하면
    //y = {(y2 - y1)(y4 - y3)(x1 - x3) + y3(x4 - x3)(y2 - y1) - y1(x2 - x1)(y4 - y3)} / {(y2 - y1)(x4 - x3) - (y4 - y3)(x2 - x1)}

   

    //공통 분모, 만약 0일 경우 평행임
    double P = (P2.second - P1.second) * (P4.first - P3.first) - (P4.second - P3.second) * (P2.first - P1.first);


    //평행인 경우
    if (P == 0)
    {
        if (P2 < P1) swap(P1, P2);
        if (P4 < P3) swap(P3, P4);
        if (P1 == P4) cout << P1.first << " " << P1.second;
        else if(P2 == P3) cout << P2.first << " " << P2.second;
        return;
    }
    

    double X = ((P3.second - P1.second) * (P2.first - P1.first) * (P4.first - P3.first) +
                P1.first * (P2.second - P1.second) * (P4.first - P3.first) -
                P3.first * (P4.second - P3.second) * (P2.first - P1.first)) / P;
    double Y = ((P2.second - P1.second) * (P4.second - P3.second) * (P1.first - P3.first) +
                P3.second * (P4.first - P3.first) * (P2.second - P1.second) -
                P1.second * (P2.first - P1.first) * (P4.second - P3.second)) / P;

    cout << fixed; 
    cout.precision(10);
    cout << X << " " <<  Y;
}

//CCW 알고리즘
int ccw(Point A, Point B, Point C)
{
    ll temp1 = A.first * B.second + B.first * C.second + C.first * A.second;
    ll temp2 = A.second * B.first + B.second * C.first + C.second * A.first;
    ll result = temp1 - temp2;

    if (result < 0) return -1;
    else if (result == 0) return 0;
    else return 1;
}

//판정
bool is_crossed(Point P1, Point P2, Point P3, Point P4)
{
    int ccw1 = ccw(P1, P2, P3);
    int ccw2 = ccw(P2, P3, P4);
    int ccw3 = ccw(P3, P4, P1);
    int ccw4 = ccw(P4, P1, P2);

    bool is_crossed;

    //직선일 때
    if (ccw1 * ccw4 == 0 && ccw2 * ccw3 == 0)
    {
        if (P2 < P1) swap(P1, P2);
        if (P4 < P3) swap(P3, P4);

        //겹쳤으면
        if (P1 <= P4 && P3 <= P2) return true;
        else return false;
    }

    return ccw1 * ccw4 <= 0 && ccw2 * ccw3 <= 0;
}

int main()
{
    Point P1, P2, P3, P4;

    cin >> P1.first >> P1.second >> P2.first >> P2.second;
    cin >> P3.first >> P3.second >> P4.first >> P4.second;

    if (is_crossed(P1, P2, P3, P4))
    {
        cout << 1 << "\n";
        get_point(P1, P2, P3, P4);
    }
    else cout << 0;

    return 0;
}

 

그 외


식이 너무 길어서 전개하다가 비명횡사 할 뻔 했습니다...

저작자표시 (새창열림)

'공부 및 정리 > 백준 코드' 카테고리의 다른 글

[C++]백준 - 2162번 문제  (0) 2021.11.11
[C++]백준 - 1350번 문제  (0) 2021.11.11
[C++]백준 - 1949번 문제  (0) 2021.11.06
[C++]백준 - 2533번 문제  (0) 2021.11.06
[C++]백준 - 2213번 문제  (0) 2021.11.05
  • 20149번 : 선분 교차 3
  • 입력
  • 출력
  • 생각해 볼 점
  • 코드
  • 그 외
'공부 및 정리/백준 코드' 카테고리의 다른 글
  • [C++]백준 - 2162번 문제
  • [C++]백준 - 1350번 문제
  • [C++]백준 - 1949번 문제
  • [C++]백준 - 2533번 문제
Plite
Plite
개발 일지, 게임 이야기 등을 적어두는 공간입니다.

티스토리툴바

단축키

내 블로그

내 블로그 - 관리자 홈 전환
Q
Q
새 글 쓰기
W
W

블로그 게시글

글 수정 (권한 있는 경우)
E
E
댓글 영역으로 이동
C
C

모든 영역

이 페이지의 URL 복사
S
S
맨 위로 이동
T
T
티스토리 홈 이동
H
H
단축키 안내
Shift + /
⇧ + /

* 단축키는 한글/영문 대소문자로 이용 가능하며, 티스토리 기본 도메인에서만 동작합니다.