포트폴리오목록으로

[level 2] 당구 연습 - 169198

· Updated

문제 링크

성능 요약

메모리: 75.6 MB, 시간: 1.22 ms

구분

코딩테스트 연습 > 연습문제

채점결과

정확성: 100.0
합계: 100.0 / 100.0

제출 일자

2024년 06월 26일 01:14:11

문제 설명

프로그래머스의 마스코트인 머쓱이는 최근 취미로 당구를 치기 시작했습니다.

머쓱이는 손 대신 날개를 사용해야 해서 당구를 잘 못 칩니다. 하지만 끈기가 강한 머쓱이는 열심히 노력해서 당구를 잘 치려고 당구 학원에 다니고 있습니다.

오늘도 당구 학원에 나온 머쓱이에게 당구 선생님이"원쿠션"(당구에서 공을 쳐서 벽에 맞히는 걸 쿠션이라고 부르고, 벽에 한 번 맞힌 후 공에 맞히면 원쿠션이라고 부릅니다) 연습을 하라면서 당구공의 위치가 담긴 리스트를 건네줬습니다. 리스트에는 머쓱이가 맞춰야 하는 공들의 위치가 담겨있습니다. 머쓱이는 리스트에 담긴 각 위치에 순서대로 공을 놓아가며 "원쿠션" 연습을 하면 됩니다. 이때, 머쓱이는 항상 같은 위치에 공을 놓고 쳐서 리스트에 담긴 위치에 놓인 공을 맞춥니다.

머쓱이와 달리 최근 취미로 알고리즘 문제를 풀기 시작한 당신은, 머쓱이가 친 공이 각각의 목표로한 공에 맞을 때까지 최소 얼마의 거리를 굴러가야 하는지가 궁금해졌습니다.

당구대의 가로 길이 m, 세로 길이 n과 머쓱이가 쳐야 하는 공이 놓인 위치 좌표를 나타내는 두 정수 startX, startY, 그리고 매 회마다 목표로 해야하는 공들의 위치 좌표를 나타내는 정수 쌍들이 들어있는 2차원 정수배열 balls가 주어집니다. "원쿠션" 연습을 위해 머쓱이가 공을 적어도 벽에 한 번은 맞춘 후 목표 공에 맞힌다고 할 때, 각 회마다 머쓱이가 친 공이 굴러간 거리의 최솟값의 제곱을 배열에 담아 return 하도록 solution 함수를 완성해 주세요.

단, 머쓱이가 친 공이 벽에 부딪힐 때 진행 방향은 항상 입사각과 반사각이 동일하며, 만약 꼭짓점에 부딪힐 경우 진입 방향의 반대방향으로 공이 진행됩니다. 공의 크기는 무시하며, 두 공의 좌표가 정확히 일치하는 경우에만 두 공이 서로 맞았다고 판단합니다. 공이 목표 공에 맞기 전에 멈추는 경우는 없으며, 목표 공에 맞으면 바로 멈춘다고 가정합니다.

직사각형 당구대에서 공 A가 오른쪽 벽에 반사되어 목표 공에 닿는 경로

위 그림은 친 공이 벽에 맞았을 때의 움직임을 나타낸 그림입니다. 치기 전 공의 위치가 점 A입니다.

공 A에서 왼쪽 위 목표 공을 향해 진행하는 직사각형 당구대 예시

위 그림은 친 공이 꼭짓점에 맞았을 때의 움직임을 나타낸 그림입니다. 치기 전 공의 위치가 점 A입니다.


제한사항
  • 3 ≤ m, n ≤ 1,000
  • 0 < startX < m
  • 0 < startY < n
  • 2 ≤ balls의 길이 ≤ 1,000
  • balls의 원소는 [a, b] 형태입니다.
    • a, b는 머쓱이가 맞춰야 할 공이 놓인 좌표를 의미합니다.
    • 0 < a < m, 0 < b < n
    • (a, b) = ( startX, startY )인 입력은 들어오지 않습니다.

입출력 예
mnstartXstartYballsresult
101037[[7, 7], [2, 7], [7, 3]][52, 37, 116]

입출력 예 설명

입출력 예 #1

  • 첫 번째 예시의 첫번째 공에 대한 그림은 다음과 같습니다.
    공 A (3,7)에서 윗벽에 반사되어 목표 공 (7,7)에 도달하는 경로

  • 당구대의 좌측 하단 좌표가 (0, 0) 입니다.

  • 점 A는 머쓱이가 칠 공이 놓인 위치입니다.

  • 점 A → 점[0] : 점선을 따라 이동하면 거리의 제곱이 52로 최소가 됩니다.

  • 같은 예시의 두 번째 공에 대한 그림은 다음과 같습니다.
    공 A (3,7)에서 윗벽에 반사되어 목표 공 (2,7)에 도달하는 경로

  • 점 A → 점[1] : 점선을 따라 이동하면 거리의 제곱이 37로 최소가 됩니다.

    • 점 A에 놓인 공을 왼쪽 방향으로 x축과 수평이 되도록 보내면 벽에 맞고 점 [1]에 닿아 이동 거리가 더 짧아보이지만, A가 벽으로 이동하는 경로에 점 [1]이 있으므로, 벽에 맞기전에 공에 먼저 맞게 됩니다.
  • 같은 예시의 세 번째 공에 대한 그림은 다음과 같습니다.
    공 A (3,7)에서 왼쪽 벽에 반사되어 목표 공 (7,3)에 도달하는 경로

  • 점 A → 점[2] : 점선을 따라 이동하면 거리의 제곱이 116으로 최소가 됩니다.

  • 따라서 [52, 37, 116]을 return 합니다.


※ 공지 - 2023년 3월 20일 문제 난이도가 Lv. 1 → Lv. 2로 변경되었습니다.

출처: 프로그래머스 코딩 테스트 연습, https://school.programmers.co.kr/learn/challenges

풀이

Java

public class Solution {
    
    public int[] solution(int m, int n, int startX, int startY, int[][] balls) {
        
        int[] answer = new int[balls.length];
        Ball ball = new Ball(startX, startY);
        ball.setWidth(m);
        ball.setHeight(n);
        
        for (int i=0; i<balls.length; i++) {
            int targetX = balls[i][0];
            int targetY = balls[i][1];
            ball.setTargetX(targetX);
            ball.setTargetY(targetY);
            answer[i] = ball.getMin();
        }
        
        return answer;
        
    }
    
}

class Ball {
    
    private int startX;
    private int startY;
    private int targetX;
    private int targetY;
    private int width;
    private int height;
    public Ball(int startX, int startY) {
        this.startX = startX;
        this.startY = startY;
    }

    public int getMin() {
        
        //target 위치를 기준으로 점대칭
        int up = pow(startX - targetX) + pow(2 * height - startY - targetY);
        int down = pow(startX - targetX) + pow(startY + targetY);
        int left = pow(startX + targetX) + pow(startY - targetY);
        int right = pow(startY - targetY) + pow(2 * width - startX - targetX);

        //상 점대칭 불가
        if (startX == targetX && targetY > startY) {
            return min(down, left, right);
        }
        
        //하 점대칭 불가
        else if (startX == targetX && targetY < startY) {
            return min(up, left, right);
        }
        
        //좌 점대칭 불가
        else if (startY == targetY && targetX > startX) {
            return min(up, down, left);
        }
        
        //우 점대칭 불가
        else if (startY == targetY && targetX < startX) {
            return min(up, down, right);
        } else {
            return min(up, down, left, right);
        }
        
    }

    public int pow(int num) {
        return (int)Math.pow(num, 2);
    }

    public int min(int... num) {
        int min = Integer.MAX_VALUE;
        for (int n : num) {
            min = Math.min(min, n);
        }
        return min;
    }

    public void setTargetX(int targetX) {
        this.targetX = targetX;
    }

    public void setTargetY(int targetY) {
        this.targetY = targetY;
    }

    public void setWidth(int width) {
        this.width = width;
    }

    public void setHeight(int height) {
        this.height = height;
    }
}
privacy.md

개인정보 처리방침

이 사이트는 김상훈의 포트폴리오와 기술 블로그입니다. 회원가입, 댓글, 결제 기능은 제공하지 않습니다.

방문 분석

공식 운영 도메인에서 Google Analytics 4, Vercel Web Analytics와 Speed Insights를 사용해 페이지 방문, 유입 경로와 성능을 확인합니다. 개발·미리보기 환경에는 분석 도구를 활성화하지 않습니다.

Google Analytics는 브라우저 식별을 위해 쿠키를 사용할 수 있으며 페이지 URL, 브라우저·기기 정보와 상호작용을 처리합니다. URL과 입력 내용에 이름, 이메일 등 개인정보를 포함하지 마세요. 이 사이트는 이메일이나 연락처를 분석 이벤트로 직접 전송하지 않습니다.

Vercel 분석 도구는 방문 통계와 로딩·응답 성능을 처리합니다. Google과 Vercel의 실제 보관 기간 및 처리는 각 서비스 설정과 정책에 따릅니다.

외부 콘텐츠와 브라우저 저장

블로그에 포함된 외부 이미지는 해당 이미지 서버에서 불러오며 해당 서버에 접속 정보가 전달될 수 있습니다. 글꼴은 이 사이트 서버에서 제공합니다. 테마 선택은 브라우저 로컬 저장소에 저장됩니다.

문의

이메일로 보낸 내용은 문의에 답변하는 데 사용됩니다. 문의: rlatkdgns042@naver.com

· © 2026 Sanghun Kim