ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • 백준 17142
    Java/코딩테스트 2023. 4. 8. 22:30

    https://www.acmicpc.net/problem/17142

     

    17142번: 연구소 3

    인체에 치명적인 바이러스를 연구하던 연구소에 승원이가 침입했고, 바이러스를 유출하려고 한다. 바이러스는 활성 상태와 비활성 상태가 있다. 가장 처음에 모든 바이러스는 비활성 상태이고

    www.acmicpc.net

    후........이거 정말 15번은 제출한 것 같다. 말이 15번이지 진짜 몇시간 내내 계속 붙들고 있었음. 계속 시간초과가 떠서 뭐가 문젠지 계속 살폈었는데 허무하게도 내가 조합 구하는 함수 재귀호출 하는 부분에서 변수를 잘못 넣었었다. 답은 제대로 나오지만 왜 시간초과가 났는지 모르겠어서 다른 분 코드보고 읽고 하다가 겨우 찾았다.... 내 코드에선 너무나 까막눈이 되는 것.. BFS쪽 잘못 짠 거 같아서 계속 여기만 디버깅하고 팠었는데 ㅋㅋㅋㅋㅋ 다른 부분이었다. 

     


    💉 변수

    - 방향용 배열인 dirX, dirY 

    - 바이러스 위치 저장용 ArrayList<Pos> virus

    - 활성화된 바이러스(조합에서 선택된) 위치용 ArrayList<Pos> selected;

    - n : 연구소 크기, m : 활성화 시킬 바이러스 

    - empty : 빈칸 크기, 채워진 칸 수가 얘랑 같아지면 탐색 끝내고 minTime 출력

    - minTime : 최소 시간 갱신용, empty == 퍼뜨려진 칸 개수일 때 갱신한다. 처음엔 Integer.MAX_VALUE로 초기화할 것

    - visited[][] 바이러스 조합 당 각 칸 당 퍼질 때까지 얼마나 시간 소요되는지 저장용 

    public static int[] dirX = { 1, 0, -1, 0}; 
    public static int[] dirY = {0, 1, 0, -1};
    public static int[][] map;
    public static ArrayList<Pos> virus;
    public static ArrayList<Pos> selected;
    public static int n, m, empty, minTime;

    💉메인로직 

    - 만약 빈칸 개수가 0이면 그냥 0출력하고 바로 끝낸다

    - 가능한 바이러스 조합을 하나씩 구한다(백트래킹 - 재귀)

    - 한 조합 당 spread()를 통해 다 퍼지는데 얼마나 걸리는지 확인한다. 

    - 바이러스가 다 퍼졌다면 마지막 칸의 visit[][] 값과 minTime 값을 비교하여 갱신한다. 

    - 만약 minTime이 Integer.MIN 아니면 고대로 출력. 아니면 -1 출력(어떤 방법을 써도 다채우지 못했다는 뜻이므로)

     

    💉 코드

    메인 함수

    public static void main(String[] args) throws IOException {
            BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
            StringTokenizer st = new StringTokenizer(br.readLine());
    
            n = Integer.parseInt(st.nextToken());
            m = Integer.parseInt(st.nextToken());
    
            empty = 0;
            minTime = Integer.MAX_VALUE;
            map = new int[n][n];
            virus = new ArrayList<>();
            selected = new ArrayList<>();
    
            for (int i = 0; i < n; i++) {
                st = new StringTokenizer(br.readLine());
                for (int j = 0; j < n; j++) {
                    int value = Integer.parseInt(st.nextToken());
                    if (value == 0) {
                        empty++;
                    }
                    else if (value == 2) {
                        virus.add(new Pos(i, j));
                    }
                    map[i][j] = value;
                }
            }
    
            if (empty == 0) {
                System.out.println(0);
            } else {
                combination(0,0);
                System.out.println(minTime == Integer.MAX_VALUE ? -1 : minTime);
            }
    
    
        }

     

    가능한 바이러스 위치 조합을 구하기( combination()  )

    public static void combination(int cur, int count) {
            if (count == m) {
                spread();
                return;
            }
            for (int i = cur; i < virus.size(); i++) {
                selected.add(virus.get(i));
                combination(i+1, count + 1); // 이걸 cur+1로 넣어서 시간초과가 났었다.. 
                selected.remove(virus.get(i));
            }
    }

    BFS 방식으로 해당 칸 기준 4방향을 탐색하며 퍼뜨리기 (spread)

    💉💉💉 중요 ! 

    - visited[nextX][nextY] = 0인 경우 2가지를 생각해야 한다. 

    - 진짜 빈칸인 경우 -> count를 증가 (퍼트린 칸수)

    - 비활성화된 바이러스인 경우 -> count 증가시키면 안됨!!! 

    public static void spread () {
            Queue<Pos> queue = new LinkedList<>();
            int[][] visited = new int[n][n];
            // 먼저 큐에 바이러스의 위치들을 기록한다. 방문했다는 뜻에서 1로 초기화  
            for (int i = 0; i < selected.size(); i++) {
                queue.add(selected.get(i));
                visited[selected.get(i).x][selected.get(i).y] = 1;
            }
            int count = 0;
            while (!queue.isEmpty()) {
                Pos pos = queue.poll();
                for (int i = 0; i < 4; i++) {
                    int nextX = pos.x + dirX[i];
                    int nextY = pos.y + dirY[i];
                    Pos next = new Pos(nextX, nextY);
                    if (!isValid(next) || map[nextX][nextY] == 1 || visited[nextX][nextY] != 0) {
                        continue;
                    }
                    
                    if (visited[nextX][nextY] == 0) {
                        if (map[nextX][nextY] == 0) {
                            count++; // 빈칸인 경우만 count 증가!! 
                        }
                        visited[nextX][nextY] = visited[pos.x][pos.y] + 1;
                        queue.add(next);
                        if (count == empty) {
                            minTime = Math.min(minTime, visited[nextX][nextY] - 1);
                        }
                    }
                }
            }
    }

     

    'Java > 코딩테스트' 카테고리의 다른 글

    프로그래머스 Stack / Queue 문제풀이 - Java  (0) 2023.04.21
    백준 23290  (0) 2023.04.08
    백준 15686  (0) 2023.04.06
    백준 14503  (0) 2023.04.06
    [ DFS / BFS ] 개념 및 예제 정리  (0) 2023.04.05
Designed by Tistory.