카테고리 없음
백준 1393 자바(Java) 음하철도 구구팔 - 수선의 발, 반직선
서병렬
2025. 3. 3. 22:53
태그
- 기하학
- 수선의 발
- 반직선
특징
수선의 발을 구하면 풀리는 간단한 문제가 아닌, 수선의 발이 철도의 경로내에 존재하는지 까지 고려해야하는, 즉 수선의 발, 선분위의 점 의 2개의 개념이 필요한 문제이다.
아래의 Mermaid 다이어그램으로 요약이 가능하다.
아래는 위의 Mermaid 다이어그램 코드이다.
graph TD
수선의발 --> 경로{철도경로
내에존재}
경로 -->|YES|B[수선의발이
최단거리지점]
경로 -->|NO|A[출발점이
최단거리지점]
코드
나의 경우는 반직선, 수선의 발에 대한 개념을 객체화로 해결하려고 했으나, 사실 이 문제를 풀기위해서는 이렇게까지 복잡한 구현이 필요없긴하다…
*** 문제에서 사용된 메서드만 표현해서 아래와 같은 구현이 불필요해 보일 수 있지만, 기하학에 주로 사용되는 로직들을 미리 구현해서 문제풀이에 활용하고 있으며 꽤 편리하다
static void solve() throws Exception {
int targetX = scan.nextInt();
int targetY = scan.nextInt();
int sx = scan.nextInt();
int sy = scan.nextInt();
int dx = scan.nextInt();
int dy = scan.nextInt();
Point2D targetPoint = new Point2D(targetX, targetY);
Point2D startPoint = new Point2D(sx, sy);
Vector2D vector = new Vector2D(dx, dy);
Line2D line = new Line2D(startPoint, vector);
// 수선의 발
Point2D foot = line.getFoot(targetPoint);
Ray2D ray = new Ray2D(startPoint, vector);
// 다이어그램 내 로직
if (ray.isOn(foot)) {
sb.append(Math.round(foot.x)).append(' ').append(Math.round(foot.y)).append('\\n');
} else {
sb.append(startPoint.x).append(' ').append(startPoint.y).append('\\n');
}
}
// 2차원에서의 점 - 직선,반직선 정의에 사용
static class Point2D {
double x;
double y;
public Point2D(double x, double y) {
this.x = x;
this.y = y;
}
}
// 2차원 방향벡터 - 직선,반직선 정의에 사용
static class Vector2D {
double x;
double y;
public Vector2D(double x, double y) {
this.x = x;
this.y = y;
}
public double dot(Vector2D other) {
return x * other.x + y * other.y;
}
public double getLengthSquare() {
return x * x + y * y;
}
}
// 2차원 직선 - 수선의 발 계산에 사용
static class Line2D {
Point2D p;
Vector2D v;
public Line2D(Point2D p1, Vector2D v) {
this.p = p1;
this.v = v;
}
public Point2D getFoot(Point2D p1) {
Vector2D pToP1 = new Vector2D(p, p1);
double dot = pToP1.dot(v);
double vLengthSquare = v.getLengthSquare();
return p.add(v.multiply(dot / vLengthSquare));
}
}
// 2차원 반직선 - 수선의 발이 반직선 위에 있는지 검사
static class Ray2D {
Point2D p;
Vector2D v;
public Ray2D(Point2D p1, Vector2D v) {
this.p = p1;
this.v = v;
}
public boolean isOn(Point2D p1) {
Vector2D vec2 = new Vector2D(p, p1);
if (crossProduct(vec2, v) == 0) {
return vec2.dot(v) > 0;
}
return false;
}
}
// 두 벡터의 외적
public static double crossProduct(Vector2D v1, Vector2D v2) {
return Math.abs(v1.x * v2.y - v1.y * v2.x);
}