문제풀이/백준oj

[백준OJ] 16973번 직사각형 탈출 - Java

Hyeon-Uk 2022. 12. 31. 02:27
반응형

https://www.acmicpc.net/problem/16973

 

16973번: 직사각형 탈출

크기가 N×M인 격자판에 크기가 H×W인 직사각형이 놓여 있다. 격자판은 크기가 1×1인 칸으로 나누어져 있다. 격자판의 가장 왼쪽 위 칸은 (1, 1), 가장 오른쪽 아래 칸은 (N, M)이다. 직사각형의 가장

www.acmicpc.net


풀이

일반적으로 BFS를 이용하여 문제를 푸는데 주의해야할 것이 있습니다.

한 칸이 아닌 직사각형을 움직이기 때문에 직사각형 범위내에 1이 있는지를 확인해야하는데, 여까지 완전탐색을 진행한다면 Time Out이 날것입니다.

따라서 이 로직을 줄여야 하는데, 여기서 누적합을 이용하여 문제를 해결해주면 시간복잡도를 줄일 수 있습니다. 

예를들어

0 0 0 0 0
0 0 1 0 0
0 0 0 0 0
0 0 0 0 0

와 같이 있으면 누적합을 이용하여

0 0 0 0 0
0 0 1 1 1
0 0 0 0 0
0 0 0 0 0

로 누적합을 구해줍니다.

 

이런 뒤 , (2,2) ~ (3,4) 까지 벽이 있는지 확인해보기 위해서는 2번째 행에서 sum[2][4] - sum[2][1] = 2 가 되기때문에 벽이 있다고 판별할 수 있게됩니다. 이를 직사각형이 걸친 모든 행을 검사하며 BFS를 수행해줍니다.

 

코드

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.Arrays;
import java.util.LinkedList;
import java.util.Queue;
import java.util.StringTokenizer;

public class Main {
    static int answer = Integer.MAX_VALUE;
    static int N, M, H, W, SR, SC, FR, FC;
    static int[][] maze;
    static int[][] sum;

    public static class Node {
        int x, y;

        public Node(int x, int y) {
            this.x = x;
            this.y = y;
        }
    }
	
    //누적합을 이용하여 벽이 있는지 검사
    public static boolean containWall(int x, int y) {
        for (int i = x; i <= x + H - 1; i++) {
            if (sum[i][y + W - 1] - sum[i][y - 1] > 0) return true;
        }
        return false;
    }

	//갈 수 있는칸인지 검사
    public static boolean isIn(int x, int y) {
        return (1 <= x && x + H - 1 <= N && 1 <= y && y + W - 1 <= M && !containWall(x, y));
    }

    public static int bfs() {
        int[][] visited = new int[N + 1][M + 1];
        int[][] mv = new int[][]{{0, 1}, {0, -1}, {1, 0}, {-1, 0}};
        for (int i = 1; i <= N; i++) Arrays.fill(visited[i], Integer.MAX_VALUE);

        Queue<Node> q = new LinkedList<>();
        q.offer(new Node(SR, SC));
        visited[SR][SC] = 0;

        while (!q.isEmpty()) {
            Node node = q.poll();
            int x = node.x;
            int y = node.y;
            int cost = visited[x][y];

            if (x == FR && y == FC) {
                return cost;
            }

            for (int d = 0; d < 4; d++) {
                int nx = x + mv[d][0];
                int ny = y + mv[d][1];

                if (isIn(nx, ny) && visited[nx][ny] > cost + 1) {
                    visited[nx][ny] = cost + 1;
                    q.offer(new Node(nx, ny));
                }
            }
        }
        return -1;
    }

    public static void main(String[] args) throws IOException {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        StringTokenizer st = new StringTokenizer(br.readLine());
        N = Integer.valueOf(st.nextToken());
        M = Integer.valueOf(st.nextToken());

        maze = new int[N + 1][M + 1];
        sum = new int[N + 1][M + 1];
        for (int i = 1; i <= N; i++) {
            st = new StringTokenizer(br.readLine());
            for (int j = 1; j <= M; j++) {
                maze[i][j] = Integer.valueOf(st.nextToken());
                sum[i][j] = maze[i][j] + sum[i][j - 1];
            }
        }

        st = new StringTokenizer(br.readLine());
        H = Integer.valueOf(st.nextToken());
        W = Integer.valueOf(st.nextToken());
        SR = Integer.valueOf(st.nextToken());
        SC = Integer.valueOf(st.nextToken());
        FR = Integer.valueOf(st.nextToken());
        FC = Integer.valueOf(st.nextToken());

        System.out.println(bfs());
    }
}
반응형