https://www.acmicpc.net/problem/17386
17386번: 선분 교차 1
첫째 줄에 L1의 양 끝 점 x1, y1, x2, y2가, 둘째 줄에 L2의 양 끝 점 x3, y3, x4, y4가 주어진다. 세 점이 일직선 위에 있는 경우는 없다.
www.acmicpc.net
#include <stdio.h>
bool CrossCheck(int ax1, int ay1, int ax2, int ay2, int bx1, int by1, int bx2, int by2)
{
//중심점을 구하고 해당 점으로부터의 방향을 외적을 이용하여 찾아낸다.
int baseX = ax1 - ax2;
int baseY = ay1 - ay2;
int x1 = bx1 - ax2;
int x2 = bx2 - ax2;
int y1 = by1 - ay2;
int y2 = by2 - ay2;
//백만 * 백만이 될 수 있어 정수형은 오버플로우 될 수 있다.
long long cross1 = (long long)baseX * y1 - (long long)baseY * x1;
long long cross2 = (long long)baseX * y2 - (long long)baseY * x2;
if (cross1 == 0 || cross2 == 0) //같은 위치에 점이 있는 경우!
{
return 0; //교차로 할거면 1, 여기선 아니라고 해두었다.
}
if ((cross1 > 0 && cross2 > 0) ||
(cross1 < 0 && cross2 < 0)) //중심점을 기준으로 양쪽이 같은 방향이면 교차x
{
return 0;
}
return 1;
}
int main()
{
int ax1, ax2, ay1, ay2, bx1, bx2, by1, by2;
int cross;
scanf("%d %d %d %d", &ax1, &ay1, &ax2, &ay2);
scanf("%d %d %d %d", &bx1, &by1, &bx2, &by2);
cross = CrossCheck(ax1, ay1, ax2, ay2, bx1, by1, bx2, by2);
if (cross > 0) //성공하면 중심점을 바꿔서 한번 더 해본다.
{
cross = CrossCheck(bx1, by1, bx2, by2, ax1, ay1, ax2, ay2);
}
printf("%d\n", cross);
}
수학 관련된 문제..
벡터의 외적을 통해 방향을 알아내는 식으로 작성된 코드이다.
외적은 다음과 같은 행렬의 여인수(cofactor) 전개를 통해서 구할 수 있다.
아래처럼 일단 외적 계산을 위한 행렬을 배치해보자.
E1 = (1, 0, 0), E2 = (0, 1, 0), E3 = (0, 0, 1)
E1 E2 E3
x1 y1 z1
x2 y2 z2
2차원 공간이기 때문에 z1과 z2는 무조건 0이다!
그렇기 때문에 행렬식을 전개해보면 다음과 같이 된다.
E1 * ( y1 * z2(0) - z1(0) * y2 ) = 0
-E2 * ( x1 * z2(0) - z1(0) * x2 ) = 0
E3 * ( x1 * y2 - y1 * x2 ) = ??
즉 x1 * y2 - y1 * x2 계산을 통해 외적을 구할 수 있게 된다.
중심 선을 기준으로 오른쪽에 위치하면 마이너스가 나오게 되고,
왼쪽에 위치하면 플러스가 나오고 겹쳐 있다면 0이 나온다.
확인을 해보도록 하자!
위의 CrossCheck 코드를 보면
먼저 baseX, baseY 를 구하고 있다. 어느 지점을 기준으로 왼쪽 오른쪽을 판별할지를 결정하는 것이고,
특정한 점을 기준으로 좌표를 계산해주고 있다. (코드는 (3, 3) ax2, ay2 를 기준으로 삼고 있다.)
위의 그림의 경우는 (3, 3)이 중심이 된다고 가정하면
(1, 1) => (1, 1) - (3, 3) = (-2, -2)
(3, 5) => (3, 5) - (3, 3) = (0, 2)
(4, 3) => (4, 3) - (3, 3) = (1, 0)
이 된다. 이러한 그림이 되는 것이고, 중심점인 빨강 선을 기준으로 외적을 구한다.
0, 2에 대해서 외적을 구해보면
-2 -2
0 2 ==> (-2 * 2) - (-2 * 0) = -4
음수값이 나온다. 즉 시계 방향(오른쪽)에 위치하고 있다.
0, 1에 대해서 외적을 구해보면
-2 -2
1 0 ==> (-2 * 0) - (-2 * 1) = 2
양수값이 나오며 시계 반대방향(왼쪽)에 위치하고 있다고 판별이 된다.
우선 선분이 교차할 가능성이 생겨있게 된다. 교차할 수 없는 경우는
모두 양수 또는 음수가 나온 경우이다. (cross1 > 0 && cross2 > 0) || (cross1 < 0 && cross2 < 0)
빨간 선을 기준으로 판별한 결과 교차할 수 있다고 나왔다.
이번엔 파란 선을 기준으로 다시 판별을 해줘야 한다.
마찬가지로 기준점을 하나 잡아 준다. 위의 코드에선 a와 b에 대해서 순서가 바뀐 것을 확인할 수 있다.
(기준 점은 빨간 선, 파란 선을 구성하는 어느 점을 선택하든 결과는 똑같다!! <- 이걸 확인해보고 싶었다 ㅎㅎ)
파란선의 방향은 아래쪽이고.. 이러한 경우는 외적 결과가 오른쪽에 2개가 있다고 나올 것이므로
두 개의 선분은 교차하지 않는다. 파란 선을 기준으로도 왼쪽, 오른쪽이 나온다면 두 선분은
교차하게 된다. 설명을 잘 못해서 너무 길어졌네.. 어쨋든 나중에도 기억하도록!!
'Algorithm > Baekjoon Online Judge' 카테고리의 다른 글
[백준 문제 C++] 1039 교환 (0) | 2021.07.28 |
---|---|
[백준 문제 C++] 1072 게임 (0) | 2021.07.18 |
[백준 문제 C++] 3109 빵집 (0) | 2021.07.07 |
[백준 문제 C++] 17780 새로운 게임 (0) | 2021.06.29 |
[백준 문제 C++] 17406 배열 돌리기 4 (0) | 2021.05.11 |