코딩테스트/문제풀이

[코드트리] 거울에 레이저 쏘기 2

알렉스 페레이라 2023. 4. 21. 09:29

여러번 풀어봤지만 잘 안풀려서 해설을 보고 분석하려고 한다. 어려움난이도는 아직 확실히 어려운거같다.

 


N * N 크기의 격자 안에 각 칸마다 거울이 하나씩 들어 있습니다. 각 거울은 \ /의 형태를 띄고있고, 격자 밖 4N개의 위치 중 특정 위치에서 레이저를 쏘았을 때, 거울에 튕기는 횟수를 구하는 프로그램을 작성해보세요.

 

입력 형식

첫 번째 줄에 N이 주어집니다.

두 번째 줄부터 N개의 줄에 걸쳐 맵의 정보가 주어집니다. 각 줄에는 각 행에 해당하는 정보가 공백없이 주어집니다. 이는 /나 \ 문자로만 이루어져 있습니다.

그 다음 줄에는 레이저를 쏘는 위치 K가 주어집니다. K는 다음과 같이 위에서 아래 방향으로 1행 1열 칸으로 들어오는 곳을 1번으로 하여 시계 방향으로 돌며 가능한 시작 위치에 순서대로 번호를 붙여 4N 번을 마지막으로 했을 때의 번호들 중 하나의 값으로 주어집니다.

 

  • 1 ≤ N ≤ 1,000
  • 1 ≤ K ≤ 4N

 

출력 형식

주어진 위치를 잡아 레이저를 쐈을 때 거울에 튕기는 횟수를 출력합니다.

 

입출력 예제

예제1

입력:

3
/\\
\\\
/\/
2

 

출력:

3

 

예제 설명

아래와 같이 2번 위치에서 시작하면 총 3번 튕기게 됩니다.

 

 

내 코드

import java.util.Scanner;

public class Main {
    public static int[][] arr;

    public static int n, K, r, c, d;

    //초기위치를 잡는다.
    public static void initialize(int num) {
        if(num <= n) {
            r = 0;
            c = num - 1;
            d = 2;
        }else if(num <= 2 * n) {
            r = num - n - 1;
            c = n - 1;
            d = 3;
        }else if(num <= 3 * n) {
            r = n - 1;
            c = n - (num - 2 * n);
            d = 0;
        }else {
            r = n - (num - 3 * n);
            c = 0;
            d = 1;
        }
    }

    public static boolean inRange(int r, int c) {
        return 0 <= r && r < n && 0 <= c && c < n;
    }

    public static void move(int nextD) {
        int[] dx = new int[]{-1,  0, 1, 0};
        int[] dy = new int[]{0, 1,  0, -1};

        r += dx[nextD];
        c += dy[nextD];
        d = nextD;
    }

    public static int simulate() {
        int moveNum = 0;
        while(inRange(r, c)) { //현재 레이저가 범위안에 있다면
            if (arr[r][c] == 0) { //거울의 모양에따라
                if(d == 0) d =1;  //거울에 튕겨나가는 레이저의 방향을 재지정해준다.
                if(d == 1) d =0;  
                if(d == 2) d =3;
                if(d == 3) d =2;  

                move(d);// 0 <-> 1 / 2 <-> 3   
            } else {                                       //-> 다음 거울로 이동
                move(3 - d);// 0 <-> 3 / 1 <-> 2
            }
            moveNum += 1;  //지금 거울에서 한번 튕겼으니 튕긴횟수 + 1
        }

        return moveNum;
    }

    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        n = sc.nextInt();
        arr = new int[n][n];


        //초기 데이터 삽입
        for(int i = 0; i < n; i++) {
            String[] mirrors = sc.next().split("");
            for(int j = 0; j < mirrors.length; j++)
                arr[i][j] = mirrors[j].equals("/") ? 0 : 1; //0 -> [/], 1 -> [\]
        }

        K = sc.nextInt();
        initialize(K);

        System.out.print(simulate());
    }
}

 

시작위치를 사각형 돌아다니면서 채우기로 알아내려고 해서 소스가 길어졌었다. 시작위치는 사실상 하드코딩느낌으로 잡을 수 있었고, 내가 제일 헷갈렸던건 레이저가 거울에 튕기기 시작하는 시점에서 다음 시점까지 index값이 어떻게 변하는지 였는데, 직접 debug해보면서 한단계씩 실행해보니 이해가 됐다.

 

  1. 현재 지점이 범위안에있다면
  2. 현재지점의 거울에 모양에 따라 레이저방향을 바꿔준다
  3. 다음칸으로 이동한다.
  4. 현재 거울에 튕겼으니 횟수를 1 늘려준다.
  5. 다시 1번으로 이동, 1번을 만족하지 않는다면 횟수를 return