N x N
크기의 복도에서 T(선생님)
, S(학생)
, X(빈칸)
이 배치되어 있다.O
가 있으면 감시를 막을 수 있다.X
) 중에서 3개의 장애물을 선택하는 모든 경우를 시도해야 한다.N x N
크기이므로, X
의 개수가 많지 않다면 3중 반복문으로 해결 가능."YES"
출력."NO"
출력.import java.io.*;
import java.util.*;
public class Main {
/*
* 특정 장애물을 미리 설치해두고 선생님의 좌표를 돌아가면서
* 선생님이 학생을 한 명이라도 발견할 수 있을지를 판단해서 해결
* 특정 장애물을 설치하는 것은 3중 반복문으로 해결,
* 만약 장애물의 개수가 많아진다면 백트래킹으로 해결 가능
* 선생님의 좌표에서 4가지 방향으로 특정 장애물, 선생님, 학생을 만날 때까지 반복해서 이동
* 선생님들 중 한 명이라도 학생을 발견하면 실패이므로 AND 연산 사용
*/
private static StringTokenizer st;
private static BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
private static int N;
private static char[][] map;
private static List<int[]> teacherPoints = new ArrayList<>();
public static void main(String[] args) throws IOException {
setting();
System.out.println(findAnswer() ? "YES" : "NO");
}
private static boolean findAnswer() {
for (int j1 = 0; j1 < N * N; j1++) {
if (map[j1 / N][j1 % N] == 'X') {
map[j1 / N][j1 % N] = 'O';
for (int j2 = j1 + 1; j2 < N * N; j2++) {
if (map[j2 / N][j2 % N] == 'X') {
map[j2 / N][j2 % N] = 'O';
for (int j3 = j2 + 1; j3 < N * N; j3++) {
if (map[j3 / N][j3 % N] == 'X') {
map[j3 / N][j3 % N] = 'O';
boolean isAnswerFind = true;
for (int[] teacher : teacherPoints) {
isAnswerFind &= !findStudent(teacher[0], teacher[1]);
}
if (isAnswerFind) return true;
map[j3 / N][j3 % N] = 'X';
}
}
map[j2 / N][j2 % N] = 'X';
}
}
map[j1 / N][j1 % N] = 'X';
}
}
return false;
}
private static boolean findStudent(int tx, int ty) {
int[] dix = {-1, 0, 1, 0};
int[] diy = {0, 1, 0, -1};
for (int i = 0; i < 4; i++) {
int dx = tx + dix[i];
int dy = ty + diy[i];
while (dx >= 0 && dx < N && dy >= 0 && dy < N) {
if (map[dx][dy] == 'O' || map[dx][dy] == 'T') break;
if (map[dx][dy] == 'S') return true;
dx += dix[i];
dy += diy[i];
}
}
return false;
}
private static void setting() throws IOException {
N = Integer.parseInt(br.readLine());
map = new char[N][N];
for (int i = 0; i < N; i++) {
st = new StringTokenizer(br.readLine());
for (int j = 0; j < N; j++) {
map[i][j] = st.nextToken().charAt(0);
if (map[i][j] == 'T') teacherPoints.add(new int[]{i, j});
}
}
}
}
함수 | 역할 |
---|---|
setting() | N x N 복도를 입력받고, 선생님 위치 저장 |
findAnswer() | 3개의 장애물을 설치하는 모든 경우 탐색 |
findStudent(tx, ty) | 특정 선생님이 감시하는 학생이 있는지 검사 |
printMap() | (디버깅용) 현재 맵 상태 출력 |
N^2
개의 빈칸에서 3개를 선택 → O(N^6)N ≤ 6
이므로 완전 탐색 가능!findStudent
) M
에 대해 4방향 탐색 → O(MN)O(N^6 * M * N) ≈ O(6^6 * 5 * 6) ≈ O(46656)
✅ 완전 탐색(브루트포스) + 시뮬레이션을 활용한 문제
✅ 백트래킹을 활용하면 N
이 커져도 확장 가능
✅ N ≤ 6
이므로 3중 반복문으로 해결 가능! 🚀
🔹 N
이 커지면 백트래킹(DFS) 방식으로 최적화 가능!
private static boolean backtrack(int count, int start) {
if (count == 3) return findAnswer(); // 장애물 3개 배치 완료 시 체크
for (int i = start; i < N * N; i++) { // start부터 탐색하여 중복 방지
int x = i / N, y = i % N;
if (map[x][y] == 'X') {
map[x][y] = 'O'; // 장애물 배치
if (backtrack(count + 1, i + 1)) return true; // 다음 위치부터 탐색
map[x][y] = 'X'; // 원상 복구
}
}
return false;
}
👉 findAnswer()
대신 backtrack(0)
을 호출하면 재귀 방식으로 최적화 가능! 🚀