문제 링크 : https://school.programmers.co.kr/learn/courses/30/lessons/169198
이 문제는 선대칭을 이용하여 문제를 풀 수 있습니다. 이 문제의 핵심은 쿠션에 맞고 나온 당구공의 위치를 파악하는 것입니다. 당구공의 위치는 선대칭을 이용하여 풀 수 있습니다. 당구장의 각 방향, 즉 상하좌우 방향으로 당구공이 이동할 경우 이동할 방향의 당구장 벽에 당구공을 대칭시킨 좌표와 시작 지점 사이의 거리가 곧 문제에서 요구하는 거리가 됩니다. 그 이유는 입사각과 반사각이 같기 때문에 각이 형성된 직선, 즉 당구장 벽면을 기준으로 하나의 공을 대칭시키면 두 직선 사이의 마주보는 사이각이 같다는 법칙으로 인해 이 공 역시 거리가 같게 되며, 직선 사이의 거리 공식을 이용하여 더 쉽게 구할 수 있기 때문입니다.
하지만 여기서 주의할 점이 있습니다. 바로 시작 공보다 타겟 공이 더 앞서 있는 경우입니다. 이 경우는 해당 방향으로 선대칭한 값으로 거리가 정해지는 것이 아니라 반대쪽 쿠션으로 넘어가야 시작공이 벽에 맞을 수 있기 때문에 시작 공보다 타겟 공이 더 앞서 있는 경우는 경로 계산에 포함하면 안됩니다.
다음은 코드입니다.
import java.util.*;
class Solution {
static int N,M,sy,sx;
public List<Integer> solution(int m, int n, int startX, int startY, int[][] balls) {
List<Integer> answer = new ArrayList<>();
N = n; M = m; sy = startY; sx = startX;
for(int[] ball : balls){
Ball curr = new Ball(ball[1],ball[0]);
answer.add(curr.getMinDistance());
}
return answer;
}
static class Ball{
int y;
int x;
Ball(int y, int x){
this.y = y;
this.x = x;
}
int getMinDistance(){
int res = Integer.MAX_VALUE;
List<Ball> balls = new ArrayList<>();
// 위 방향 이동
if(!(x==sx && y<sy)) balls.add(new Ball(y*-1,x));
// 아래 방향 이동
if(!(x==sx && y>sy)) balls.add(new Ball(2*N-y,x));
// 왼쪽 방향 이동
if(!(y==sy && x<sx)) balls.add(new Ball(y,x*-1));
// 오른쪽 방향 이동
if(!(y==sy && x>sx)) balls.add(new Ball(y,2*M-x));
for(Ball ball : balls){
int diffY = Math.abs(sy-ball.y);
int diffX = Math.abs(sx-ball.x);
int d = (int)Math.pow(diffY,2) + (int)Math.pow(diffX,2);
res = Math.min(res,d);
}
return res;
}
}
}