Algorithm

백준 14846번 <직사각형과 쿼리>

seungh2 2023. 11. 20. 20:55

백준 알고리즘 14846번

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

 

14846번: 직사각형과 쿼리

첫째 줄에 N (1 ≤ N ≤ 300)이 주어진다. 다음 N개의 줄에는 행렬의 정보가 주어지며, 각 줄은 N개의 수로 이루어져 있다. 행은 위에서부터 아래로, 열은 왼쪽부터 오른쪽으로 번호가 매겨져 있으며

www.acmicpc.net


14846번

N행 N열로 이루어진 정사각형 행렬 A가 주어진다. 이때, 쿼리를 수행하는 프로그램을 작성하시오.

  • x1 y1 x2 y2: 왼쪽 윗칸이 (x1, y1)이고, 오른쪽 아랫칸이 (x2, y2)인 부분 행렬에 포함되어 있는 서로 다른 정수의 개수를 출력한다.

문제 해결

누적합을 이용해서 문제를 풀었다.

 

행렬 A가 있다고 할 때, 누적 숫자의 개수를 담은 check 배열을 만들었다.

check[i][j] = (i, j) 좌표를 사각형의 오른쪽 아래라고 생각했을 때, 그 사각형에 포함된 숫자의 개수를 가진 배열

위의 그림과 같이 check[1][1]의 배열을 구할 수 있고, 위의 행렬에 대해 모두 구했을 때는 아래와 같다.

 

누적합인 check 배열을 구하는 방법은 다음과 같다.

  • check[0][0]은 a[0][0]만 1인 int 형 배열이다.
  • check[i][0]은 check[i-1][0]에서 a[i][0]번째 값에 +1을 한다.
  • check[0][j]은 check[0][j-1]에서 a[0][j]번째 값에 +1을 한다.
  • check[i][j]는 check[i][j-1]의 값에 각각 check[i-1][j]의 값을 더하고 check[i-1][j-1]의 값을 빼준다.

 

x1, y1, x2, y2 연산을 하는 방법은 다음과 같다.


코드

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;

public class BOJ_14846 {
    static int N;
    static int[][] input;
    static int[][][] check;
    public static void main(String[] args) throws IOException {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));

        N = Integer.parseInt(br.readLine());
        input = new int[N][N];
        for (int i = 0; i < N; i++) {
            String[] inArr = br.readLine().split(" ");
            for (int j = 0; j < N; j++) {
                input[i][j] = Integer.parseInt(inArr[j]);
            }
        }

        // check[i][j] : (i, j)까지 누적 숫자의 개수
        check = new int[N][N][11];
        check[0][0][input[0][0]] = 1;
        for (int i = 1; i < N; i++) {
            check[i][0] = deepcopy(check[i - 1][0]);
            check[i][0][input[i][0]] ++;
            check[0][i] = deepcopy(check[0][i-1]);
            check[0][i][input[0][i]] ++;
        }
        for (int i = 1; i < N; i++) {
            for (int j = 1; j < N; j++) {
                check[i][j] = minus(plus(check[i-1][j], check[i][j-1]), check[i-1][j-1]);
                check[i][j][input[i][j]]++;
            }
        }

        StringBuilder sb = new StringBuilder();
        int M = Integer.parseInt(br.readLine());
        for (int i = 0; i < M; i++) {
            String[] inArr = br.readLine().split(" ");
            int x1 = Integer.parseInt(inArr[0]) - 1;
            int y1 = Integer.parseInt(inArr[1]) - 1;
            int x2 = Integer.parseInt(inArr[2]) - 1;
            int y2 = Integer.parseInt(inArr[3]) - 1;
            int[] answer = check[x2][y2];
            if (x1 - 1 >= 0) {
                answer = minus(answer, check[x1 - 1][y2]);
            }
            if (y1 - 1 >= 0) {
                answer = minus(answer, check[x2][y1 - 1]);
            }
            if (x1 - 1 >= 0 && y1 - 1 >= 0) {
                answer = plus(answer, check[x1 - 1][y1 - 1]);
            }
            sb.append(count(answer)).append("\n");
        }
        System.out.println(sb);
    }

    static int count(int[] arr) {
        int cnt = 0;
        for (int i = 0; i < 11; i++) {
            if (arr[i] > 0) {
                cnt++;
            }
        }
        return cnt;
    }

    static int[] deepcopy(int[] arr) {
        int[] copy = new int[11];
        for (int i = 0; i < 11; i++) {
            copy[i] = arr[i];
        }
        return copy;
    }

    static int[] plus(int[] a, int[] b) {
        int[] arr = new int[11];
        for (int i = 0; i < 11; i++) {
            arr[i] = a[i] + b[i];
        }
        return arr;
    }
    static int[] minus(int[] a, int[] b) {
        int[] arr = new int[11];
        for (int i = 0; i < 11; i++) {
            arr[i] = a[i] - b[i];
        }
        return arr;
    }
}

결과

 


 

728x90