https://www.acmicpc.net/problem/2636
2636번: 치즈
첫째 줄에는 사각형 모양 판의 세로와 가로의 길이가 양의 정수로 주어진다. 세로와 가로의 길이는 최대 100이다. 판의 각 가로줄의 모양이 윗 줄부터 차례로 둘째 줄부터 마지막 줄까지 주어진
www.acmicpc.net
걸린 시간 : 47분 43초
생각이 너무 안 나서 답답했던 문제였다. 공기와 닿은 부분을 어떻게 찾을까 고민을 많이 했지만, 결국 실행마다 공기를 모두 찾아주고, 치즈를 모두 탐색해서 구현하는 것이었다. 이렇게 매 실행마다 해도, 실행은 최대 50번이고, 배열의 크기가 최대 100이라서 가능하다는 것을 알아차려야 했다.
알고리즘
배열은 0 ~ N+1 까지 있고 0과 N+1 부분은 가장자리이다. 사진에서 X 표시 부분이다. 즉 여기서 주의해야 할 점은, 여러가지 로직을 수행하는 범위가 0 ~ N-1 이 아니라 1 ~ N 이라는 것이다.

- 입력 시 1 ~ N 부분을 채워야 한다. 0과 N+1 부분은 전역으로 생성해 0으로 채워져 있다. 이 때 총 치즈 개수를 세어 total 변수에 넣는다.
- 이제 공기가 닿는 부분에는 0이 아니라 2로 계속 바꿔나갈 것이다. 우선 (0, 0)을 2로 바꿔준다.
- while 문 안에서 다음을 반복한다. while문 마지막 즈음에 남은 치즈 개수를 확인해 다 먹었으면 그 때 break;한다.
- 먼저, 사진의 파란색 빗금 부분을 모조리 2로 채워야 한다. 이 부분은 DFS로 한다. 방문 체크를 위한 vis 배열은 실행 직전 0으로 초기화한다. (memset 함수를 사용하면 더 좋은 코드가 될 것 같다.)
- 시간을 증가시킨다.
- 모든 부분을 돌아보면서 치즈 부분 중에 주변에 공기가 있다면 willmelt 벡터에 삽입한다.
- total 변수에 willmelt의 크기를 빼서 남은 치즈 개수를 센다. 만약 0이라면 치즈가 다 녹은 것이므로 시간 (cnt)와 이번에 녹는 치즈 개수 (willmelt.size()) 를 출력하고 break; 한다.
- 치즈가 다 녹지 않았다면 willmelt 벡터에 있는, 즉 녹는 치즈 부분들을 공기가 채워졌다는 의미로 2로 바꿔준다.
정답코드
#include <bits/stdc++.h> using namespace std; int N, M, cnt, total; int board[105][105]; int vis[105][105]; int di[4] = {-1, 0, 0, 1}; int dj[4] = {0, -1, 1, 0}; void pushair(int i, int j) { for (int k = 0; k < 4; k++) { int ni = i + di[k]; int nj = j + dj[k]; if (ni < 0 || ni > N+1 || nj < 0 || nj > M+1 || board[ni][nj] == 1 || vis[ni][nj] == 1) continue; vis[ni][nj] = 1; board[ni][nj] = 2; pushair(ni, nj); } } int main(void) { ios::sync_with_stdio(0); cin.tie(0); cin >> N >> M; for (int i = 1; i <= N; i++) { for (int j = 1; j <= M; j++) { cin >> board[i][j]; if (board[i][j] == 1) total++; } } if (total == 0) { cout << 0 << "\n" << 0; return 0; } board[0][0] = 2; while(1) { for (int i = 0; i <= N+1; i++) { fill(vis[i], vis[i]+M, 0); } vis[0][0] = 1; pushair(0, 0); vector<pair<int, int> > willmelt; cnt++; for (int i = 1; i <= N; i++) { for (int j = 1; j <= M; j++) { if (board[i][j] != 1) continue; if (board[i-1][j] == 2 || board[i+1][j] == 2 || board[i][j-1] == 2 || board[i][j+1] == 2) { willmelt.push_back({i, j}); } } } total -= willmelt.size(); if (total == 0) { cout << cnt << "\n" << willmelt.size(); break; } for (auto coordinate : willmelt) { board[coordinate.first][coordinate.second] = 2; } } return 0; }
'Baekjoon Online Judge' 카테고리의 다른 글
[BOJ] 17828 : 문자열 화폐 (C++) (0) | 2023.09.21 |
---|---|
[BOJ] 20058 : 마법사 상어와 파이어스톰 (C++) (1) | 2023.09.07 |
[BOJ] 2110 : 공유기 설치 (C++) (0) | 2023.09.05 |
[BOJ] 1339 : 단어 수학 (C++) (0) | 2023.09.03 |
[BOJ] 3055 : 탈출 (C++) (0) | 2023.08.30 |