[dalsu0222] BOJ_색종이_만들기_cpp #22
Open
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
🔗 문제 링크
[Silver 2] 백준 2630번 색종이 만들기 https://www.acmicpc.net/problem/2630

n x n 크기의 색종이가 주어진다. 각 정사각형들은 하얀색으로 칠해져 있거나 파란색으로 칠해져 있다. 주어진 종이를 일정한 규칙에 따라 잘라서 다양한 크기를 가진 정사각형 모양의 하얀색 또는 파란색 색종이를 만들려고 한다.
이를 자르는 규칙은 다음과 같다.
전체 종이가 모두 같은 색으로 칠해져 있지 않으면 가로와 세로로 중간 부분을 잘라서 <그림 2>의 I, II, III, IV와 같이 똑같은 크기의 네 개의 N/2 × N/2색종이로 나눈다. 나누어진 종이 I, II, III, IV 각각에 대해서도 앞에서와 마찬가지로 모두 같은 색으로 칠해져 있지 않으면 같은 방법으로 똑같은 크기의 네 개의 색종이로 나눈다. 이와 같은 과정을 잘라진 종이가 모두 하얀색 또는 모두 파란색으로 칠해져 있거나, 하나의 정사각형 칸이 되어 더 이상 자를 수 없을 때까지 반복한다.
입출력입력으로 주어진 종이의 한 변의 길이 N과 각 정사각형칸의 색(하얀색 또는 파란색)이 주어질 때 잘라진 하얀색 색종이와 파란색 색종이의 개수를 구하는 프로그램을 작성하시오.
예제 입력 18
1 1 0 0 0 0 1 1
1 1 0 0 0 0 1 1
0 0 0 0 1 1 0 0
0 0 0 0 1 1 0 0
1 0 0 0 1 1 1 1
0 1 0 0 1 1 1 1
0 0 1 1 1 1 1 1
0 0 1 1 1 1 1 1
예제 출력 19
7
💡 풀이 아이디어
☑️처음 접근한 방법
4등분할때마다 4개의 새로운 정사각형이 새로 계속 생겨나고, 각각의 4등분된 정사각형은 길이는 전부 (자르기 전 정사각형 길이)/4 로 동일할테지만 , 4등분된 정사각형은 전부 시작지점이 달라질 것입니다.(왼쪽 위 꼭짓점이 전부 달라짐)
💬 풀이 과정
☑️사용한 변수
int n: 초기 정사각형 길이int paper[130][130]: 입력받는 n x n 색종이를 저장할 변수. 1 <= n <= 128이므로, 크기는 여유롭게 [130][130]으로 선언해주었습니다.int white, blue: 결과로 출력할 잘라진 햐얀색 색종이의 개수, 파란색 색종이의 개수에 해당합니다.☑️풀이
void countPaper(int x, int y, int side)함수bool isAllSame = true: 탐색하고자 하는 구역이 전부 색상이 동일한지 저장하는 상태 변수 입니다. true로 설정하여, 추후 다른 값이 발견될경우, false로 업데이트할 예정입니다.int color = paper[x][y]: 시작지점 (x,y)에 해당하는 색깔을 초기 색상 값으로 설정하고, 나머지 값들이 이와 같은지 체크합니다.color와 다른 색깔이 등장한다면,isAllSamebool 변수를 false로 업데이트하고 실행시간을 조금이라도 줄이기 위해 바로 반복문을 빠져나왔습니다.isAllSame값에 따라 색종이를 더 자를지 말지 판단합니다.true이면 전부 동일한 색상이어서 더 자를 필요가 없으므로, 해당 색상의 색종이 개수를 1 증가시켜주고 함수를 종료합니다.false이면 더 잘라야 하므로, 4등분하여 색상을 다시 확인합니다. 4등분한만큼 재귀함수를 4번 사용하여 각 4등분하는 색종이의 시작지점을 달리하여 색상을 체크해줍니다.countPaper()함수의 경우 rside = 1일때는 무조건isAllSame = true가 되므로 무한루프에 빠지지 않게 됩니다.😥 겪었던 어려움
함수 인자의 설정
반복되는 과정을 함수화해야되는 것까지는 접근하였는데, 함수화 과정에서 어떤 인자가 필요한지 결론을 도출해내는데에 확신이 서지 않아 많은 시간을 할애하게 된 것 같습니다.
실행 시간 1초의 고려
실행시간을 1초로 해결해야하는데, 재귀함수에서 2차 반복문을 쓴다는 것이 꽤나 큰 리스크로 다가왔고 시간 초과가 뜨는것은 아닌가 걱정했습니다. 다행히 2차 반복문 안에서 다른 색상이 발견될때 바로 상태변수를 업데이트하고 반복문을 빠져나왔더니, 잘 해결된것 같습니다.
하지만 체스판처럼 이웃한 색종이 색이 전부 다른 최악의 경우 O(n*n)의 실행시간이 생길수도 있을거 같긴한데 (의문?) 다행히 이번 문제에서는 n의 최댓값이 128으로 그렇게 크지 않아 가능했던 것 같습니다.
📚 참고 자료
이 문제에 대한 다른 풀이에 대해 찾아보니, 색종이 자르기 문제가
분할 정복문제였습니다.분할 정복 알고리즘 (분할정복 알고리즘에 관한 글을 찾아 첨부하였습니다. 궁금하신 분들은 읽어보세요!!)
분할정복 알고리즘은 그대로 해결할 수 없는 문제를 작은 문제로 분할하여 문제를 해결하는 방법인데, 재귀알고리즘이 가장 많이 쓰이지만 일반 재귀함수와 다른점은 나눠지는 데이터의 크기가 거의 일정하다는 것입니다.
또한 분할 정복의 알고리즘들은 O(nlogn)의 실행 시간을 가져서, 위에서 최악의 실행경우에 O(N*N)일것 같다고 했는데 분할 정복의 문제인 경우 **O(nlogn)**이 됨을 처음 알게 되었습니다.
분할 정복이라는 새로운 알고리즘을 ... 알게되어 기쁘기도 하지만 아직 가야할 길이 멀었음을 느꼈습니다 😓