[BAEKJOON] 1915. 가장 큰 정사각형
Posted on
문제 :
n×m의 0, 1로 된 배열이 있다. 이 배열에서 1로 된 가장 큰 정사각형의 크기를 구하는 프로그램을 작성하시오.
위와 같은 예제에서는 가운데의 2×2 배열이 가장 큰 정사각형이다.
입력 :
첫째 줄에 n, m(1 ≤ n, m ≤ 1,000)이 주어진다. 다음 n개의 줄에는 m개의 숫자로 배열이 주어진다.
출력 :
첫째 줄에 가장 큰 정사각형의 넓이를 출력한다.
풀이 :
꽤나 오래 전에 풀어본 기억이 나는 문제였는데, 당시에는 다이나믹 프로그래밍 방식으로 접근하는 것이 익숙치 않아서 전혀 감을 잡지 못했던 문제로 기억한다. 그래서 오늘 한번 풀어보자 생각하고 구현해보았다.
우선 가장 큰 정사각형의 넓이를 찾는 문제이기에 인덱스마다 얼마나 큰 정사각형이 있는지 모두 찾는 방법은 중복과정이 너무 많을 것 같았다. 때문에 DP 방식을 사용해야 할 것이라는 생각이 들었다. 그래서 생각해낸 방식은 그림으로 먼저 설명하자면,
가로, 세로 길이가 2인 작은 정사각형으로 모두 고려하면 문제가 편할 것 같았다. 위의 그림과 같이 최소값에 1씩 더해주면 현재 인덱스에서 가능한 최대 정사각형 한 변의 길이를 구할 수 있다. 때문에 마지막까지 메모이제이션을 실행해주면 전체 input 값의 최대 정사각형 값을 구할 수 있다.
알고리즘을 시작한 지 얼마 되지 않았을 때에는 DP로 접근 자체가 안되서 어려움이 있었으나 지금은 어느 정도 DP로 접근은 가능한 것 같다. 하지만 내 방식에도 여전히 중복된 연산 과정이 존재하기 때문에 더 최적화된 알고리즘을 생각해 볼 필요가 있다.
코드 :
코드 보기/접기
#include <iostream>
#include <algorithm>
#define MAX 1000
using namespace std;
int ary[MAX][MAX];
int main() {
int n, m, i, j, k, di[3] = { 0, 1, 1 }, dj[3] = { 1, 1, 0 }, cmpi, cmpj, minval, ans = 0;
char num;
cin >> n >> m;
for (i = 0; i < n; i++)
for (j = 0; j < m; j++) {
cin >> num;
ary[i][j] = num - '0';
}
for (i = n - 1; i >= 0; i--)
for (j = m - 1; j >= 0; j--) {
if (!ary[i][j]) continue;
minval = 1111;
for (k = 0; k < 3; k++) {
cmpi = i + di[k];
cmpj = j + dj[k];
if (cmpi >= n || cmpj >= m || !ary[cmpi][cmpj]) break;
minval = min(minval, ary[cmpi][cmpj]);
}
if (k >= 3) ary[i][j] = minval + 1;
ans = max(ans, ary[i][j]);
}
cout << ans * ans << '\n';
}