[BOJ] 9944. NxM 보드 완주하기

Problem

제출일 : 2020-02-13

문제 풀이 시간 : 1H 30M

난이도 : ★★★☆


link : https://www.acmicpc.net/problem/9944

N×M 보드 위에서 할 수 있는 게임이 있다. 보드는 크기가 1×1인 정사각형 칸으로 나누어져 있다. 보드의 각 칸은 빈 칸 또는 장애물이다. 장애물은 아래 그림에선 어두운 사각형으로 표시되어져 있다.

게임을 시작하려면 보드의 빈 칸 위에 공을 하나 놓아야 한다. 아래 그림에서 공은 회색 점으로 표시되어져 있다. 게임은 단계로 이루어져 있고, 각 단계는 아래와 같이 구성되어져 있다.

  • 위, 아래, 오른쪽, 왼쪽 중 방향 하나를 고른 다음, 그 방향으로 공을 계속해서 이동시킨다.
  • 공은 장애물, 보드의 경계, 이미 공이 지나갔던 칸을 만나기 전까지 계속해서 이동한다.

게임은 공이 더 이상 이동할 수 없을 때 끝난다. 이 때, 모든 빈 칸을 공이 방문한 적이 있어야 한다.

아래 그림은 총 10단계 만에 모든 칸을 방문하는 방법이다.

img

보드의 상태가 주어졌을 때, 모든 칸을 방문하기 위한 이동 횟수의 최솟값을 구하는 프로그램을 작성하시오.

Input

입력은 여러 개의 테스트 케이스로 이루어져 있다.

각 테스트 케이스의 첫째 줄에는 보드의 크기를 나타내는 N과 M이 주어진다. N은 세로 크기, M은 가로 크기이고, 두 값은 30보다 작거나 같은 자연수이다. 둘째 줄부터 N개의 줄에는 보드의 상태가 주어진다. 보드의 상태는 장애물을 나타내는 '*'과 빈 칸을 나타내는 '.'으로 이루어져 있다.

입력으로 주어진 보드가 장애물로만 이루어진 경우는 없다.

Output

각 테스트 케이스마다 보드의 모든 빈 칸을 방문하는 최소 이동 횟수를 출력한다. 출력 형식은 예제를 참고한다.

만약, 모든 빈 칸을 방문할 수 없다면 최소 이동 횟수는 -1이다.

Example

input

5 5
**...
.....
....*
..*..
.....
3 4
****
*...
*..*

output

Case 1: 10
Case 2: 3

Solution & Inpression

색다른 DFS문제 + 입력의 개수가 정해지지 않았기 때문에 EOF 처리로 종료

출력 부분 대소문자와 띄어쓰기를 유의하여야 한다. >> 이부분을 찾느라 1시간이 넘게 걸림.....

Code

언어 : JAVA

메모리 : 20,148 kb

실행시간 : 356 ms

import java.util.Scanner;

public class Main {
    static int N, M, ans;
    static int[][] map;
    // 상 하 좌 우
    static int[] dr = { -1, 1, 0, 0 };
    static int[] dc = { 0, 0, -1, 1 };

    public static void main(String[] args) throws Exception {
        //System.setIn(new FileInputStream("res/input.txt"));
        Scanner sc = new Scanner(System.in);
        int TC = 0;
        while (sc.hasNext()) {
            N = sc.nextInt();
            M = sc.nextInt();
            map = new int[N][M];
            int blank = -1; // 빈 칸의 개수
            for (int i = 0; i < N; i++) {
                String str = sc.next();
                for (int j = 0; j < M; j++) {
                    if (str.charAt(j) == '*')
                        map[i][j] = 1;
                    else {
                        map[i][j] = 0;
                        blank++;
                    }
                }
            }

            ans = 123456789;
            for (int i = 0; i < N; i++) {
                for (int j = 0; j < M; j++) {
                    if (map[i][j] == 0) {
                        map[i][j] = 1;
                        DFS(i, j, 0, blank);
                        map[i][j] = 0;
                    }
                }
            }
            if (ans == 123456789)
                ans = -1;
            System.out.println("Case " + ++TC + ": " + ans);
        }
    }

    private static void DFS(int i, int j, int cnt, int blank) {
        if (blank == 0 && ans > cnt) {
            ans = cnt;
            return;
        }

        for (int dir = 0; dir < 4; dir++) {
            int nr = i + dr[dir];
            int nc = j + dc[dir];
            if (isRange(nr, nc) && map[nr][nc] == 0) {
                while (isRange(nr, nc) && map[nr][nc] == 0) {
                    map[nr][nc] = 1;
                    blank--;
                    nr += dr[dir];
                    nc += dc[dir];
                }
                nr -= dr[dir];
                nc -= dc[dir];
                DFS(nr, nc, cnt + 1, blank);

                while (nr != i || nc != j) {
                    map[nr][nc] = 0;
                    blank++;
                    nr -= dr[dir];
                    nc -= dc[dir];
                }
            }

        }
    }

    private static boolean isRange(int nr, int nc) {
        if (0 <= nr && nr < N && 0 <= nc && nc < M)
            return true;
        return false;
    }
}

'Problem > BOJ' 카테고리의 다른 글

[BOJ] 4963. 섬의 개수 - DFS  (0) 2020.02.14
[BOJ] 1107. 리모컨 - BF  (0) 2020.02.14
[BOJ] 16985. Maaaaaaaaaze - Graph/BF/BFS  (0) 2020.02.12
[BOJ] 14501. 퇴사/15486. 퇴사2 - BF/DP  (0) 2020.02.06
[BOJ] 13023. ABCDE - Graph  (2) 2020.02.03