알고리즘 문제/DP
[개쉬운 풀이] 백준 1915 가장 큰 정사각형 (CPP/C++)
odaebum
2024. 3. 4. 15:32
728x90
https://www.acmicpc.net/problem/1915
1915번: 가장 큰 정사각형
첫째 줄에 n, m(1 ≤ n, m ≤ 1,000)이 주어진다. 다음 n개의 줄에는 m개의 숫자로 배열이 주어진다.
www.acmicpc.net
생각
정사각형은 무엇인가? 모든 변의 길이가 같고 모든 각이 직각을 이루는 사각형이다.
근데 문제에 각은 90도로 고정이 된 상태이고 길이만 생각을 하면 되겠구나!
그렇다면 좌측 상단부터 우측 하단으로 이동하면서 각 위치에서 만들 수 있는 가장 큰 정사각형을 구하고 마지막에 어떤 크기가 가장 큰지 보면 되겠구나라고 생각하였다.
여기서 문제는 각 위치에서 만들 수 있는 가장 큰 정사각형을 어떻게 구하냐이다.
나의 결론은 다음과 같다.
- 정사각형을 이루기 위해서는 0이 존재해서는 안된다.
- 각 위치를 dp형태로 만들 수 있는 가장 큰 정사각형을 저장하여 다음 위치에서 계산을 할 때 재계산하지 않도록 한다.
- 각 위치에서 가장 큰 정사각형 구하기 (예시)
- 현재 위치는 항상 정사각형의 우측 하단 이므로 파란색의 위치를 기준으로 정사각형의 최대를 구해보자
- map을 기준으로 현재 파란색의 위치는 1이다.
- 파란색의 위치를 기준으로 좌측 상단의 최대 정사각형 넓이를 구하므로 dp를 이용하여 빨간 밑줄 위치의 dp 정보를 이용하자.
- 왼쪽[r][c-1]과 위쪽[r-1][c]은 현재 길이가 2인 넓이의 정사각형이 최대이다. (왼쪽으로 최대 2길이 만큼 사각형 이용가능하다는 뜻)
- 좌측 상단 [r-1][c-1]은 현재 길이가 1인 넓이의 정사각형이 최대이다.
- 따라서 위 3가지의 정보를 가지고 최대 넓이를 찾아야한다.
- (조건) 만약 3가지 정보가 모두 2로 동일하다면 파란색의 위치에서 만들 수 있는 최대의 사각형은 3의 길이를 가진 정사각형이다.
- (조건) .만약 1가지 정보라도 작은 것이 있다면 그럼 최대 길이가 가장 작은 길이를 고려하여 3가지 정보 중 "가장 작은 정보 길이 + 1의 길이"를 가진 정사각형이 파란색의 위치에 해당하는 정보가 된다.
- 결론 : 3가지 고려해서 최소 정보 + 1 하면 현재 파란색의 정보임
- (조건이 두가지 이지만 어차피 첫번째 조건은 모두 동일한 정보일때이므로 가장 작은 정보와 동일하기에 코드 단축)
코드
int n, m;
int map[1001][1001];
int dp[1001][1001];
void sol(){
//i와 j를 1부터 탐색하는 이유는 어차피 그들은 왼쪽 상단이 없기 때문
for(int i = 1; i < n; i++){
for(int j = 1; j < m; j++){
//현재 위치가 1인가? (조건 1)
if(map[i][j]){
//빨간색에 해당하는 3가지 정보 모두 1인가?
if(map[i-1][j-1] && map[i-1][j] && map[i][j-1]){
int minValue = 10e8;
minValue = min(minValue, dp[i-1][j-1]);
minValue = min(minValue, dp[i][j-1]);
minValue = min(minValue, dp[i-1][j]);
dp[i][j] = minValue + 1;
}
//아니면 그냥 원래 배정받은 숫자가 최대(1)
}
}
}
int result = 0;
for(int i = 0; i < n; i++){
for(int j = 0; j < m; j++){
if(dp[i][j] > result) result = dp[i][j];
}
}
cout << result*result << endl;
}
최대 정사각형을 구하는 방법만 고려한다면 쉽게 풀 수 있다.
마지막에 우리는 길이를 기준으로 구했으니 문제 출력 조건인 넓이(길이 * 길이) 반환
전체 코드
#include <iostream>
#include <vector>
#include <algorithm>
#include <cmath>
using namespace std;
int n, m;
int map[1001][1001];
int dp[1001][1001];
void input(){
cin >> n >> m;
for(int i = 0; i < n; i++){
for(int j = 0; j < m; j++){
char c;
cin >> c;
map[i][j] = c - '0';
dp[i][j] = map[i][j];
}
}
}
void sol(){
for(int i = 1; i < n; i++){
for(int j = 1; j < m; j++){
if(map[i][j]){
if(map[i-1][j-1] && map[i-1][j] && map[i][j-1]){
int minValue = 10e8;
minValue = min(minValue, dp[i-1][j-1]);
minValue = min(minValue, dp[i][j-1]);
minValue = min(minValue, dp[i-1][j]);
dp[i][j] = minValue + 1;
}
}
}
}
int result = 0;
for(int i = 0; i < n; i++){
for(int j = 0; j < m; j++){
if(dp[i][j] > result) result = dp[i][j];
}
}
cout << result*result << endl;
}
int main(){
input();
sol();
return 0;
}
728x90