본문 바로가기
알고리즘/완전탐색

[java 백준] 골드 5/1451번 직사각형으로 나누기

by Meaning_ 2022. 2. 17.
728x90
반응형

 

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

 

1451번: 직사각형으로 나누기

첫째 줄에 직사각형의 세로 크기 N과 가로 크기 M이 주어진다. 둘째 줄부터 직사각형에 들어가는 수가 가장 윗 줄부터 한 줄에 하나씩 M개의 수가 주어진다. N과 M은 50보다 작거나 같은 자연수이

www.acmicpc.net

 

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
import java.io.IOException;
import java.util.Scanner;
 
public class Main {
 
    public static int n, m;
    public static int[][] arr;
 
    public static long sum(int ax, int ay, int bx, int by) {
        int cnt = 0;
 
        for (int i = ax; i <= bx; i++) {
            for (int j = ay; j <= by; j++) {
                cnt += arr[i][j];
            }
        }
        return cnt;
    }
 
    public static void main(String[] args) throws NumberFormatException, IOException {
        Scanner sc = new Scanner(System.in);
 
        n = sc.nextInt();
        m = sc.nextInt();
        arr = new int[n + 1][m + 1];
 
        for (int i = 0; i < n; i++) {
 
            String s = sc.next();
            for (int j = 0; j < m; j++) {
                arr[i][j] = s.charAt(j) - '0';
            }
 
        }
        // 직사각형 나누는 방법 6가지
 
        // case 1
        // 꼭짓점,끝과 끝을 sum에 넣어주는 거
        long ans = 0;
 
        for (int i = 0; i < m - 2; i++) {// 축1
            for (int j = i + 1; j < m - 1; j++) {// 축2
                long sum1 = sum(00, n - 1, i);
                long sum2 = sum(0, i + 1, n - 1, j);// i+1이 아니라 j 끝과 끝 생각
                long sum3 = sum(0, j + 1, n - 1, m - 1);
                if (ans < sum1 * sum2 * sum3) {
                    ans = sum1 * sum2 * sum3;
                }
 
            }
        }
 
        // case 2
 
        for (int i = 0; i < n - 2; i++) {
            for (int j = i + 1; j < n - 1; j++) {
                long sum1 = sum(00, i, m - 1);
                long sum2 = sum(i + 10, j, m - 1);
                long sum3 = sum(j + 10, n - 1, m - 1);
                if (ans < sum1 * sum2 * sum3) {
                    ans = sum1 * sum2 * sum3;
                }
            }
        }
 
        // case 3
        for (int i = 0; i < n - 1; i++) {// 행을 가르는 축
            for (int j = 0; j < m - 1; j++) {// 열을 가르는 축
                long sum1 = sum(00, i, m - 1);
                long sum2 = sum(i + 10, n - 1, j);
                long sum3 = sum(i + 1, j + 1, n - 1, m - 1);
                if (ans < sum1 * sum2 * sum3) {
                    ans = sum1 * sum2 * sum3;
                }
            }
        }
 
        // case 4
        for (int i = 0; i < m - 1; i++) {
            for (int j = 0; j < n - 1; j++) {
                long sum1 = sum(00, j, i);
                long sum2 = sum(0, i + 1, j, m - 1);
                long sum3 = sum(j + 10, n - 1, m - 1);
                if (ans < sum1 * sum2 * sum3) {
                    ans = sum1 * sum2 * sum3;
                }
            }
        }
 
        // case 5
        for (int i = 0; i < m - 1; i++) {// 열을 가르는
            for (int j = 0; j < n - 1; j++) {
                long sum1 = sum(00, n - 1, i);
                long sum2 = sum(0, i + 1, j, m - 1);
                long sum3 = sum(j + 1, i + 1, n - 1, m - 1);
                if (ans < sum1 * sum2 * sum3) {
                    ans = sum1 * sum2 * sum3;
                }
 
            }
 
        }
 
        // case 6
        for (int i = 0; i < m - 1; i++) {
            for (int j = 0; j < n - 1; j++) {
                long sum1 = sum(00, j, i);
                long sum2 = sum(j + 10, n - 1, i);
                long sum3 = sum(0, i + 1, n - 1, m - 1);
                if (ans < sum1 * sum2 * sum3) {
                    ans = sum1 * sum2 * sum3;
                }
            }
        }
 
        System.out.println(ans);
 
    }
}
cs

 

 

3개의 직사각형을 나눌 수 있는 방법은 총 6가지이다.

 

근데 문제는 이걸 어떻게 나눠주느냐에 있었다. 사실 너무 어려워서 다른 사람의 sum메서드 코드를 보았다. 

우선 구획한 직사각형을 더해주는 sum 메서드를 보자. 

 

1
2
3
4
5
6
7
8
9
10
 public static long sum(int ax, int ay, int bx, int by) {
        int cnt = 0;
 
        for (int i = ax; i <= bx; i++) {
            for (int j = ay; j <= by; j++) {
                cnt += arr[i][j];
            }
        }
        return cnt;
    }
cs

 

 

직사각형이 시작하는 부분부터 끝나는 부분 즉 끝과 끝의 행과 열의 index를 받아서 더해주는 방법을 생각해보았다.

결국에 직사각형의 꼭짓점들만 받아올 수 있게 코드를 짜면 되겠다는 생각이 들었다.

 

 

case 1) 

얘의 경우 열을 가르는 축 2개만 필요하다. 두개의 축을 각각 i,j라 둘건데, i는 m-2 전까지 돌 수 있고 (적어도 2칸 남겨야함),j는 m-1 전까지 돌 수 있다.(적어도 뒤에 한칸 남겨야함)

 

 

sum함수에는 (시작점 행,시작점 열,끝점 행,끝점 열)을 넣어주면 된다.

 

 

 

case2)

 

그렇다면 행을 가르는 축을 i로 두고 열을 가르는 축을 j로 두자.

위와 같은 경우를 살펴볼 것이다.

 

이 모양도 위에랑 똑같이 행을 가르는걸 i축, 열을 가르는걸 j축으로 두면 된다.

 

아까 case1이랑 달라지는건 i는 m-2가 아니라 m-1 전까지 잘릴 수 있다. 왜냐면 얘는 2등분만 하면 되기 때문에 뒤에 한부분만 남기면 되기 때문이다. j도 m-1 전까지 자를 수 있다.

 

이해하면 그 다음부턴 코드가 술술 써지는데 처음에 기준잡는게 너무 어렵다....ㅜ

참고 사이트

https://dbstndi6316.tistory.com/116

 

[백준문제풀이] 1451 직사각형으로 나누기

풀이일시 : 2020-10-15 ​ 문제 : 세준이는 N*M크기로 직사각형에 수를 N*M개 써놓았다. 세준이는 이 직사각형을 겹치지 않는 3개의 작은 직사각형으로 나누려고 한다. 각각의 칸은 단 하나의 작은 직

dbstndi6316.tistory.com

https://log-laboratory.tistory.com/128

 

[백준] 1451번 자바 직사각형으로 나누기

문제 출처 https://www.acmicpc.net/problem/1451 1451번: 직사각형으로 나누기 첫째 줄에 직사각형의 세로 크기 N과 가로 크기 M이 주어진다. 둘째 줄부터 직사각형에 들어가는 수가 가장 윗 줄부터 한 줄에

log-laboratory.tistory.com

 

728x90
반응형

댓글