※ 글쓴이는 취미로 코딩을 익혀보는 사람이라 정확하지 않은 내용을 담고 있을 수 있다 ※
이번에 볼 문제는 백준 11563번 문제인 연돌이와 고잠녀이다.
문제는 아래 링크를 확인하자.
11563번: 연돌이와 고잠녀
첫 줄에는 신촌에 연결된 도로의 개수 n과 안암에 연결된 도로의 개수 m(1 ≤ n, m ≤ 2,000)이 주어진다. 이어지는 n줄에 걸쳐 xs, ys, xe, ye가 주어진다. (-10,000 ≤ xs, ys, xe, ye ≤ 10,000) 이는 신촌에 연
www.acmicpc.net
이 문제에서는 서로 교점이 없는 두 선분들의 집합 사이의 최단거리를 구해야 한다.
각 집합의 크기가 최대 2000이므로, 가능한 모든 쌍의 선분(최대 400만쌍)에 대하여 거리를 재는 방식으로 이 문제를 풀 수 있다.
두 선분 AB와 CD 사이의 최단거리는 아래와 같은 후보들 중 하나이다.
1) AC, AD, BC, BD의 길이
2) A에서 CD에 내린 수선, B에서 CD에 내린 수선, C에서 AB에 내린 수선, D에서 AB에 내린 수선의 길이
단, 2에서 해당 수선의 발이 선분의 위가 아닌 연장선상에 있다면 그 값은 후보가 될 수 없다.
점 X에서 선분 YZ에 내린 수선의 발이 선분 위에 있는지 확인하는 방법은 내적을 이용하는 것이다. 구체적으로는 벡터 YX와 YZ의 내적, ZX와 ZY의 내적 값이 각각 양수이면 수선의 발이 선분 위에 있게 된다. (증명은 어렵지 않으므로 생략한다)
점 X와 선분 YZ 사이의 거리는 2 * (삼각형 XYZ의 넓이) / (YZ의 길이) 로 구할 수 있다.
아래는 제출한 소스코드이다.
#include <iostream>
#include <cmath>
#include <vector>
using namespace std;
typedef pair<double, double> pd;
double dist(pd pt1, pd pt2){
return sqrt((pt1.first - pt2.first) * (pt1.first - pt2.first) + (pt1.second - pt2.second) * (pt1.second - pt2.second));
}
double innerproduct(pd pt1, pd pt2, pd pt3) {
return (pt2.first - pt1.first) * (pt3.first - pt1.first) + (pt2.second - pt1.second) * (pt3.second - pt1.second);
}
double area(pd pt1, pd pt2, pd pt3) { // 수선길이 = 2 * 넓이 / 밑변길이 이므로 넓이를 구할 때 1/2를 하지 않음
return abs((pt1.first * pt2.second + pt2.first * pt3.second + pt3.first * pt1.second
- pt1.first * pt3.second - pt3.first * pt2.second - pt2.first * pt1.second));
}
double segmentdist(pd pt1, pd pt2, pd pt3, pd pt4) {
double ret = min(min(dist(pt1, pt3), dist(pt1, pt4)), min(dist(pt2, pt3), dist(pt2, pt4)));
if (innerproduct(pt1, pt3, pt2) > 0 && innerproduct(pt2, pt3, pt1) > 0)
ret = min(ret, area(pt1, pt2, pt3) / dist(pt1, pt2));
if (innerproduct(pt1, pt4, pt2) > 0 && innerproduct(pt2, pt4, pt1) > 0)
ret = min(ret, area(pt1, pt2, pt4) / dist(pt1, pt2));
if (innerproduct(pt3, pt1, pt4) > 0 && innerproduct(pt4, pt1, pt3) > 0)
ret = min(ret, area(pt3, pt4, pt1) / dist(pt3, pt4));
if (innerproduct(pt3, pt2, pt4) > 0 && innerproduct(pt4, pt2, pt3) > 0)
ret = min(ret, area(pt3, pt4, pt2) / dist(pt3, pt4));
return ret;
}
pd sinchon[2000][2];
int main() {
ios::sync_with_stdio(0);
cin.tie(0);
double ans = 100000;
int N, M; cin >> N >> M;
for (int i = 0; i < N; i++) {
double x, y, z, w; cin >> x >> y >> z >> w;
sinchon[i][0] = { x,y }, sinchon[i][1] = { z,w };
}
for (int j = 0; j < M; j++) {
double x, y, z, w; cin >> x >> y >> z >> w;
pd pt3 = { x,y }, pt4 = { z,w };
for (int i = 0; i < N; i++) {
ans = min(ans, segmentdist(sinchon[i][0], sinchon[i][1], pt3, pt4));
}
}
cout << fixed;
cout.precision(10);
cout << ans;
}
innerproduct(pt1, pt2, pt3): 벡터 pt1pt2와 벡터 pt1pt3의 내적을 계산한다.
'BOJ' 카테고리의 다른 글
[BOJ 11657 // C++] 타임머신 (0) | 2021.05.16 |
---|---|
[BOJ 1865 // C++] 웜홀 (0) | 2021.05.15 |
[BOJ 11562 // C++] 백양로 브레이크 (0) | 2021.05.13 |
[BOJ 1183 // C++] 약속 (0) | 2021.05.12 |
[BOJ 11561 // C++] 징검다리 (0) | 2021.05.11 |