🔗 문제 링크
성곽 문제는 각 칸에 4방향(서, 북, 동, 남)의 벽이 있는 성곽이 주어지고,
이 성곽에서 다음 세 가지를 구하는 문제임:
각 칸의 숫자는 벽의 유무를 비트로 표현하는데,
예를 들어, 1, 2, 4, 8은 각각 서, 북, 동, 남쪽 벽을 의미함.
인접한 칸들에서 벽이 없으면 같은 방에 속한다고 볼 수 있음.
아이디어:
방 번호와 크기 기록하기
numberMap
을 관리하고,cntByNumber
리스트에 저장함.벽 제거 시 방 합치기
(map[i][j] & (1 << k)) == (1 << k)
조건으로 판별함.장점:
아래 코드는 두 번째 시도를 반영한 최종 솔루션입니다:
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.List;
import java.util.StringTokenizer;
public class Main {
private static StringTokenizer st;
private static StringBuilder sb = new StringBuilder();
private static BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
private static int N, M;
private static int[][] map;
private static boolean[][] visited;
private static int[][] dir = {{0, -1}, {-1, 0}, {0, 1}, {1, 0}};
private static int roomCnt, maxRoomSize, removedWallMaxRoomSize;
private static int cntTmp;
private static int[][] numberMap;
private static List<Integer> cntByNumber = new ArrayList<>();
public static void main(String[] args) throws IOException {
setting();
// 각 방에 대해 DFS 실행하여 방 번호와 크기 기록
for (int i = 0; i < N; i++) {
for (int j = 0; j < M; j++) {
if (visited[i][j]) continue;
roomCnt++;
getRoomCntDfs(i, j, roomCnt - 1);
cntByNumber.add(cntTmp);
maxRoomSize = Math.max(maxRoomSize, cntTmp);
cntTmp = 0;
}
}
// (디버깅용) 방 번호 출력
// for (int i = 0; i < N; i++) {
// for (int j = 0; j < M; j++) {
// System.out.print(numberMap[i][j]);
// }
// System.out.println();
// }
// System.out.println(cntByNumber);
// 모든 칸에 대해 4방 탐색, 인접한 두 방이 다르면 벽 제거 시 합칠 수 있는 방 크기 계산
for (int i = 0; i < N; i++) {
for (int j = 0; j < M; j++) {
for (int k = 0; k < 4; k++) {
int dx = i + dir[k][0];
int dy = j + dir[k][1];
if (dx < 0 || dx >= N || dy < 0 || dy >= M) continue;
if (numberMap[i][j] == numberMap[dx][dy]) continue;
if ((map[i][j] & (1 << k)) == (1 << k)) {
removedWallMaxRoomSize = Math.max(
removedWallMaxRoomSize,
cntByNumber.get(numberMap[i][j]) + cntByNumber.get(numberMap[dx][dy])
);
}
}
}
}
sb.append(roomCnt).append("\n")
.append(maxRoomSize).append("\n")
.append(removedWallMaxRoomSize);
System.out.println(sb.toString());
}
// DFS를 통해 하나의 방에 속하는 칸의 수와 방 번호를 기록함
private static void getRoomCntDfs(int x, int y, int number) {
cntTmp++;
visited[x][y] = true;
numberMap[x][y] = number;
for (int i = 0; i < 4; i++) {
int dx = x + dir[i][0];
int dy = y + dir[i][1];
if (dx < 0 || dx >= N || dy < 0 || dy >= M) continue;
if (visited[dx][dy]) continue;
if ((map[x][y] & (1 << i)) == (1 << i)) continue; // 해당 방향에 벽이 있다면 진행하지 않음
getRoomCntDfs(dx, dy, number);
}
}
private static void setting() throws IOException {
st = new StringTokenizer(br.readLine());
M = Integer.parseInt(st.nextToken());
N = Integer.parseInt(st.nextToken());
map = new int[N][M];
visited = new boolean[N][M];
numberMap = new int[N][M];
for (int i = 0; i < N; i++) {
st = new StringTokenizer(br.readLine());
for (int j = 0; j < M; j++) {
map[i][j] = Integer.parseInt(st.nextToken());
}
}
}
}
방 탐색 (DFS) 및 방 번호 부여
visited
배열을 이용해 각 칸을 한 번씩만 탐색합니다. cntTmp
에 누적합니다. numberMap
에 기록하며,cntByNumber
리스트에 각 방의 크기를 저장합니다.벽 제거 시 방 합치기
removedWallMaxRoomSize
에 업데이트합니다.최종 결과 출력