주녘공부일지

[프로그래머스 C#] Lv.2 당구 연습 본문

Programmers - C#/CodingTest Lv.2

[프로그래머스 C#] Lv.2 당구 연습

주녘 2024. 2. 26. 16:34
728x90

https://school.programmers.co.kr/learn/courses/30/lessons/169198

 

프로그래머스

코드 중심의 개발자 채용. 스택 기반의 포지션 매칭. 프로그래머스의 개발자 맞춤형 프로필을 등록하고, 나와 기술 궁합이 잘 맞는 기업들을 매칭 받으세요.

programmers.co.kr

1. 정답코드 및 핵심 아이디어, 유의사항

원쿠션으로 공을 맞출 때 최소 거리의 제곱을 구하는 문제

 

문제에 제시된 예시로 나온 밑의 그림때문에 헷갈릴 수 있는데 고려할 필요 없음

- 애초에 꼭짓점을 맞추는 경우는 원쿠션이 아니라 투쿠션임

- 꼭짓점을 맞추는 경우는 최단 거리가 될 수 없음 

 

 

핵심 포인트) 공이 벽에 맞아 튕길 때의 입사각과 반사각은 항상 같음

- 원쿠션으로 갈 수 있는 길은 각 벽에 대해 단 하나씩만 존재 (4가지)

 -> 벽에 대해 대칭되는 좌표와의 직선거리가 원쿠션 거리와 같음

 

+ 해당하는 벽에 대해서 원쿠션으로 못 가는 경우가 있음

 ex) 벽에 대한 법선위에 두 공이 존재하는데, 맞춰야 하는 공이 벽에 더 가까운 경우

 

주석 참조

    using System;

    public class Solution
    {
        public class Pos
        {
            public int y;
            public int x;

            public Pos(int y, int x)
            {
                this.y = y;
                this.x = x;
            }
        }

        public int[] solution(int m, int n, int startX, int startY, int[,] balls)
        {
            int[] answer = new int[balls.GetLength(0)];
            Pos startPos = new Pos(startY, startX); // 시작점
            
            // 각 좌표 하나하나에 대해 최소 거리를 구함
            for (int i = 0; i < balls.GetLength(0); i++)
            {
                // 맞춰야 하는 공의 좌표
                int posY = balls[i, 1];
                int posX = balls[i, 0];
                Pos movePos;
                int minDir = int.MaxValue;

                // 오른쪽 벽에 대한 대칭 좌표 ( y = 2m - y )
                if ((posX > startPos.x && posY == startPos.y) == false)
                {
                    movePos = new Pos(posY, 2 * m - posX);
                    minDir = Math.Min(minDir, GetSquareDir(startPos, movePos));
                }

                // 위쪽 벽에 대한 대칭 좌표 ( x = 2n - x )
                if ((posY > startPos.y && posX == startPos.x) == false)
                {
                    movePos = new Pos(2 * n - posY, posX);
                    minDir = Math.Min(minDir, GetSquareDir(startPos, movePos));
                }

                // 아래쪽 벽에 대한 대칭 좌표 ( y *= -1 )
                if ((posY < startPos.y && posX == startPos.x) == false)
                {
                    movePos = new Pos(posY * -1, posX);
                    minDir = Math.Min(minDir, GetSquareDir(startPos, movePos));
                }

                // 왼쪽 벽에 대한 대칭 좌표 ( x *= -1 )
                if ((posX < startPos.x && posY == startPos.y) == false)
                {
                    movePos = new Pos(posY, posX * -1);
                    minDir = Math.Min(minDir, GetSquareDir(startPos, movePos));
                }

                answer[i] = minDir;
            }

            return answer;
        }

        // 두 점 사이의 거리의 제곱을 리턴하는 메서드
        public int GetSquareDir(Pos p1, Pos p2)
        {
            int dirY = p1.y - p2.y;
            int dirX = p1.x - p2.x;

            return (dirY * dirY) + (dirX * dirX);
        }
    }
728x90