🧫 문제 분석
✔️ 출처
📖 문제

그래프 탐색 문제
기존 벽 부수기와 달리 벽을 부쉈을때 이동가능한 칸의 개수를 부순 자리에 출력하고
벽이 아닌 곳 즉, 0인곳은 그대로 0 을 출력한다.
벽을 부쉈을때 마다 0을 탐색하는것보다
미리 0의 영역을 나눠서 탐색하여 해당 영역의 0의 개수를 구해놓고
각 벽의 위치에서 상하좌우 인접한 칸이 0인지 확인후 해당 칸의 영역에 구해놓은 0의 개수를 더하는 식으로 하면된다.
중요한 점은 영역 중복 연산 처리이다.
boolean 이중 배열로 했다가 메모리초과를 계속당했다.
Set을 사용하여 해결하였다.
✔️ Set.claer()에 대해서
set이 가능한 이유는 상하좌우 4가지에 대해서만 영역을 체크하기 때문이다.
clear()메서드는 모든 set의 요소들을 순회하면서 null로 바꿔 메모리를 해제한다.
따라서 많아야 4개밖에 없기에 set으로도 O(1) 성능을 낼 수 있다.
🔅 문제 풀이
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.IOException;
import java.util.*;
public class Main {
static int[] dy = {1, -1, 0, 0};
static int[] dx = {0, 0, 1, -1};
static int[][] map; // 전체 맵
static int[][] possibleArea; // 0인 영역의 번호
static boolean[][] zeroVisited; // 0 방문 체크
static int[] possibleCnt; // 0인 영역 별 개수
public static void main(String[] args) throws IOException {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
StringTokenizer st = new StringTokenizer(br.readLine());
int n = Integer.parseInt(st.nextToken());
int m = Integer.parseInt(st.nextToken());
map = new int[n][m];
possibleArea = new int[n][m];
zeroVisited = new boolean[n][m];
possibleCnt = new int[n * m + 1];
for (int i = 0; i < n; i++) {
String line = br.readLine();
for (int j = 0; j < m; j++) {
map[i][j] = line.charAt(j) - '0';
}
}
int number = 1; // 영역 번호
for (int i = 0; i < n; i++) {
for (int j = 0; j < m; j++) {
if (map[i][j] == 0 && !zeroVisited[i][j]) {
int cnt = bfs(i, j, number);
possibleCnt[number] = cnt; // 영역번호에 해당하는 영역 내 0 의 개수를 기록
number++;
}
}
}
int[][] answer = new int[n][m];
Set<Integer> vistiedSet = new HashSet<>();
int one = -1;
for (int i = 0; i < n; i++) {
for (int j = 0; j < m; j++) {
// 1인 벽을 중심으로 상하좌우 탐색
if (map[i][j] == 0) continue;
one++;
answer[i][j] = 1; // 1번 조건, 벽을 부수고 이동할 수 있는 곳으로 변경, 즉 1있는곳을 0으로 하여 이동가능 칸 +1
vistiedSet.clear();
// 상하좌우 탐색
for (int k = 0; k < 4; k++) {
int nextR = i + dy[k];
int nextC = j + dx[k];
// 범위를 넘어서거나 벽이거나 이미 방문했다면 다음 방향 탐색
if (n <= nextR || 0 > nextR
|| m <= nextC || 0 > nextC || map[nextR][nextC] == 1) continue;
// 탐색한 위치의 영역 번호를 얻고 영역 번호에 해당하는 영역 내 0의 개수를 얻음
int num = possibleArea[nextR][nextC];
int cnt = possibleCnt[num];
if (!vistiedSet.contains(num)) {
vistiedSet.add(num);
// 해당 벽을 부쉈을 때 이동 가능한 칸의 개수 갱신
answer[i][j] = (answer[i][j] + cnt) % 10;
}
}
}
}
StringBuilder sb = new StringBuilder();
for (int[] row : answer) {
for (int col : row) sb.append(col);
sb.append("\n");
}
System.out.print(sb.toString());
}
// 0인 영역을 BFS 탐색
private static int bfs(int r, int c, int num) {
Queue<int[]> q = new LinkedList<>();
q.add(new int[]{r, c});
zeroVisited[r][c] = true;
possibleArea[r][c] = num;
int cnt = 0;
while (!q.isEmpty()) {
int[] current = q.poll();
cnt++;
for (int i = 0; i < 4; i++) {
int nextR = current[0] + dy[i];
int nextC = current[1] + dx[i];
if (validate(nextR, nextC)) continue;
zeroVisited[nextR][nextC] = true;
possibleArea[nextR][nextC] = num;
q.add(new int[]{nextR, nextC});
}
}
return cnt;
}
private static boolean validate(int nextR, int nextC) {
return map.length <= nextR || 0 > nextR
|| map[0].length <= nextC || 0 > nextC
|| zeroVisited[nextR][nextC] || map[nextR][nextC] == 1;
}
}
❗ 오답노트 / 필요한 지식
- 때로는 Set이 더 효율적일 때가 있다.
'baekjoon > Graph_Search' 카테고리의 다른 글
백준 2632번 : 음악프로그램 [자바] (1) | 2025.05.30 |
---|---|
백준 2638번 : 치즈 [자바] (0) | 2025.04.12 |
백준 1238번 : 파티 [자바] (0) | 2025.04.10 |
백준 1504번 : 특정한 최단 경로 [자바] (0) | 2025.03.31 |
백준 1389번 : 케빈 베이컨 6단계 법칙 [자바] (0) | 2025.03.26 |