
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)을 호출하면 재귀 방식으로 최적화 가능! 🚀