알고리즘 공부/BFS

[프로그래머스] 동굴탐험

kdhoooon 2021. 5. 9. 16:54

문제


[본 문제는 정확성과 효율성 테스트 각각 점수가 있는 문제입니다.]

오지 탐험가인 프로도는 탐험 도중 n개의 방으로 이루어진 지하 동굴을 탐험하게 되었습니다. 모든 방에는 0부터 n - 1 까지 번호가 붙어있고, 이 동굴에 들어갈 수 있는 유일한 입구는 0번 방과 연결되어 있습니다. 각 방들은 양방향으로 통행이 가능한 통로로 서로 연결되어 있는데, 서로 다른 두 방을 직접 연결하는 통로는 오직 하나입니다. 임의의 서로 다른 두 방 사이의 최단경로는 딱 한 가지만 있으며, 또한 임의의 두 방 사이에 이동이 불가능한 경우는 없습니다.

탐험에 앞서 이 지하 동굴의 지도를 손에 넣은 프로도는 다음과 같이 탐험 계획을 세웠습니다.

  1. 모든 방을 적어도 한 번은 방문해야 합니다.
  2. 특정 방은 방문하기 전에 반드시 먼저 방문할 방이 정해져 있습니다.
    2-1. 이는 A번 방은 방문하기 전에 반드시 B번 방을 먼저 방문해야 한다는 의미입니다.
    2-2. 어떤 방을 방문하기 위해 반드시 먼저 방문해야 하는 방은 없거나 또는 1개 입니다.
    2-3. 서로 다른 두 개 이상의 방에 대해 먼저 방문해야 하는 방이 같은 경우는 없습니다.
    2-4. 어떤 방이 먼저 방문해야 하는 방이면서 동시에 나중에 방문해야 되는 방인 경우는 없습니다.

위 계획 중 2-2, 2-3, 2-4는 순서를 지켜 방문해야 하는 두 방의 쌍이 A → B(A를 먼저 방문하고 B를 방문함) 형태로 유일함을 의미합니다. 즉, 프로도는 아래와 같은 형태로 방문순서가 잡히지 않도록 방문 계획을 세웠습니다.

  • A → B, A → C (방문순서 배열 order = [...,[A,B],...,[A,C],...]) 형태로 A를 방문 후에 방문해야 할 방이 B와 C로 두 개 또는 그 이상인 경우
  • X → A, Z → A (방문순서 배열 order = [...,[X,A],...,[Z,A],...]) 형태로 A를 방문하기 전에 방문해야 할 방이 X와 Z로 두 개 또는 그 이상인 경우
  • A → B → C (방문순서 배열 order = [...,[A,B],...,[B,C],...) 형태로 B처럼 A 방문 후이면서 동시에 C 방문 전인 경우

그리고 먼저 방문해야 할 방과 나중에 방문할 방을 반드시 연속해서 방문해야 할 필요는 없어 A방을 방문한 후 다른 방을 방문한 후 B방을 방문해도 좋습니다.

방 개수 n, 동굴의 각 통로들이 연결하는 두 방의 번호가 담긴 2차원 배열 path, 프로도가 정한 방문 순서가 담긴 2차원 배열 order가 매개변수로 주어질 때, 프로도가 규칙에 맞게 모든 방을 탐험할 수 있을 지 return 하도록 solution 함수를 완성해주세요.

 

 

 

[제한사항]

  • n은 2 이상 200,000 이하입니다.
  • path 배열의 세로(행) 길이는 n - 1 입니다.
    • path 배열의 원소는 [방 번호 A, 방 번호 B] 형태입니다.
    • 두 방 A, B사이를 연결하는 통로를 나타냅니다.
    • 통로가 연결하는 두 방 번호가 순서없이 들어있음에 주의하세요.
  • order 배열의 세로(행) 길이는 1 이상 (n / 2) 이하입니다.
    • order 배열의 원소는 [방 번호 A, 방 번호 B] 형태입니다.
    • A번 방을 먼저 방문한 후 B번 방을 방문해야 함을 나타냅니다.

 

 

풀이


BFS를 이용해서 모든 그래프를 돌 수 있게 만들면서 풀었다.

 

대신 먼저 방문해야하는 노드와 방문한 이후에 방문할 노드를 체크해주었다.

 

1. 미리 먼저 방문해야하는 노드를 int[] 배열에 저장을한다.

2. 그래프를 0 부터 너비우선탐색 방식을 이용해서 방문한다.

3 - 1. 방문한 노드가 미리 방문해야하는 노드가 있다.

3 - 2. 방문한 노드가 미리 방문해야하는 노드가 없다.

4.  3-1의 경우는 이미 방문을 할 수 있는 노드지만 미리 방문해야하는 노드가 방문이 안된 상태기 때문에 해당 노드의 후에 방문할 노드의 번호를 넣어준다.

3-2의 경우는 visited[]를 true로 체크해준다.

 

5. 현재 노드의 방문 이후에 방문 할 수 있는 노드가 있다면 queue에 추가주어 방문해준다.

 

여기서 주의할점은 0번 노드는 무조건 시작 점이므로 이후에 방문해야하는 노드의 번호에 0이있다면 무조건 false를 출력시켜준다.

 

<전체코드>

import java.util.*;
import java.io.*;

class Solution {
    public boolean solution(int n, int[][] path, int[][] order) {
        boolean answer = true;
        
        List<Integer>[] map = new List[n];
        for(int i = 0 ; i < n ; i++){
            map[i] = new ArrayList<Integer>();
        }
        
        for(int i = 0 ; i < path.length ; i++){
            int a = path[i][0];
            int b = path[i][1];
            
            map[a].add(b);
            map[b].add(a);
        }
        
        int[] parent = new int[n];
        int[] child = new int[n];
        
        for(int i = 0 ; i < order.length ; i++){
            parent[order[i][1]] = order[i][0];
        }
        
        if(parent[0] != 0)
            return false;
        
        boolean[] visited = new boolean[n];
        Queue<Integer> queue = new LinkedList<Integer>();
        queue.add(0);
        while(!queue.isEmpty()){
            int top = queue.poll();
       
            if(top != 0 && !visited[parent[top]]){
                child[parent[top]] = top;
                continue;
            }
            
            visited[top] = true;
                
            for(int next : map[top]){
                
                if(!visited[next]){
                    queue.add(next);
                }
            }
            
            if(child[top] != 0)
                queue.add(child[top]);
        }
        
        for(int i = 0 ; i < n ; i++){
            if(!visited[i])
                return false;
        }
        
        return answer;
    }
}

'알고리즘 공부 > BFS' 카테고리의 다른 글

[백준] 1303 전쟁 - 전투  (0) 2021.08.03
[프로그래머스] 카드 짝 맞추기  (0) 2021.06.03
[프로그래머스] 가장 먼 노드  (0) 2021.05.18
백준 2206 (벽 부수고 이동하기)  (0) 2021.05.03
백준 1525 (퍼즐)  (0) 2021.04.04