[15558 - JAVA] 점프 게임

2024. 7. 21. 11:40Algorithm

 

문제

 

상근이는 오른쪽 그림과 같은 지도에서 진행하는 게임을 만들었다.

지도는 총 2개의 줄로 나누어져 있으며, 각 줄은 N개의 칸으로 나누어져 있다. 칸은 위험한 칸과 안전한 칸으로 나누어져 있고, 안전한 칸은 유저가 이동할 수 있는 칸, 위험한 칸은 이동할 수 없는 칸이다.

가장 처음에 유저는 왼쪽 줄의 1번 칸 위에 서 있으며, 매 초마다 아래 세 가지 행동중 하나를 해야 한다.

  • 한 칸 앞으로 이동한다. 예를 들어, 현재 있는 칸이 i번 칸이면, i+1번 칸으로 이동한다.
  • 한 칸 뒤로 이동한다. 예를 들어, 현재 있는 칸이 i번 칸이면, i-1번 칸으로 이동한다.
  • 반대편 줄로 점프한다. 이때, 원래 있던 칸보다 k칸 앞의 칸으로 이동해야 한다. 예를 들어, 현재 있는 칸이 왼쪽 줄의 i번 칸이면, 오른쪽 줄의 i+k번 칸으로 이동해야 한다.

N번 칸보다 더 큰 칸으로 이동하는 경우에는 게임을 클리어한 것이다.

게임을 재밌게 하기 위해서, 상근이는 1초에 한 칸씩 각 줄의 첫 칸이 사라지는 기능을 만들었다. 즉, 게임을 시작한지 1초가 지나면 1번 칸이 사라지고, 2초가 지나면 2번 칸이 사라진다. 편의상 유저가 먼저 움직이고, 칸이 사라진다고 가정한다. 즉, 이번에 없어질 칸이 3번 칸인데, 상근이가 3번 칸에 있다면, 3번 칸에서 다른 칸으로 이동하고 나서 3번 칸이 없어지는 것이다.

각 칸의 정보가 주어졌을 때, 게임을 클리어 할 수 있는지, 없는지 구하는 프로그램을 작성하시오.

 

입력

 

첫째 줄에 N과 k가 주어진다. (1 ≤ N, k ≤ 100,000)

둘째 줄에는 왼쪽 줄의 정보가 주어진다. i번째 문자가 0인 경우에는 위험한 칸이고, 1인 경우에는 안전한 칸이다. 셋째 줄에는 오른쪽 줄의 정보가 주어지고, 각 문자의 의미는 왼쪽 줄의 의미와 동일하다.

왼쪽 줄의 1번 칸은 항상 안전한 칸이다.

 

출력

 

게임을 클리어할 수 있으면 1을, 없으면 0을 출력한다.

 

풀이

 

import java.util.*;
import java.lang.*;
import java.io.*;

class Main {

    static int n, k;
    static int[][] maps;
    
    public static void main(String[] args) throws IOException {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        StringTokenizer st = new StringTokenizer(br.readLine());

        n = Integer.parseInt(st.nextToken());
        k = Integer.parseInt(st.nextToken());

        maps = new int[2][n];

        String left = br.readLine();
        String right = br.readLine();
        
        for (int i = 0; i < n; i++) {
            maps[0][i] = Integer.parseInt(left.substring(i, i + 1));
            maps[1][i] = Integer.parseInt(right.substring(i, i + 1));
        }

        System.out.println(bfs(0, 0, 0));
        
    }

    static int bfs(int x, int y, int time) {
        Queue<int[]> q = new LinkedList<>();
        boolean[][] visited = new boolean[2][n];

        q.add(new int[] {x, y, time});
        visited[x][y] = false;

        while (!q.isEmpty()) {
            int[] current = q.poll();
            int nx = current[0];
            int ny = current[1];
            int n_time = current[2];

            if (ny + k >= n) {
                return 1;
            }

            if (ny < n_time) {
                continue;
            }
            
            // + 1
            if (ny + 1 < n && !visited[nx][ny + 1] && maps[nx][ny + 1] == 1) {
                visited[nx][ny + 1] = true;
                q.add(new int[] {nx, ny + 1, n_time + 1});
            }

            // - 1
            if (ny - 1 > n_time && !visited[nx][ny - 1] && maps[nx][ny - 1] == 1) {
                visited[nx][ny - 1] = true;
                q.add(new int[] {nx, ny - 1, n_time + 1});
            }

            // + k
            if (ny + k < n && !visited[1 - nx][ny + k] && maps[1 - nx][ny + k] == 1) {
                visited[1 - nx][ny + k] = true;
                q.add(new int[] {1 - nx, ny + k, n_time + 1});
            }
        }

        return 0;
    }
}


처음 문제를 풀때 헷갈렸던 부분은 시작 위치가 고정인지 아닌지에 대해 이해가 되지 않았다. 입력 조건에서 왼쪽 줄의 1번 칸은 항상 안전한 칸이라는 조건을 보고 해당 위치에서 시작되게 작성하게 되었다. 결론적으로는 시작 위치는 항상 왼쪽 줄 1번이 맞는거 같다. 두번째로 처음 실패 코드에서는 ny + k >= n 부분을 ny >= n 으로 작성하였는데 줄을 이동하는 부분에서는 고려되지 않아 문제가 발생하였다.