ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [프로그래머스] 2021 카카오 채용연계형 인턴십 - 미로 탈출 - 자바(JAVA)
    알고리즘/프로그래머스 2022. 6. 8. 00:01
    728x90

    https://programmers.co.kr/learn/courses/30/lessons/81304

     

    코딩테스트 연습 - 미로 탈출

    4 1 4 [[1, 2, 1], [3, 2, 1], [2, 4, 1]] [2, 3] 4

    programmers.co.kr

     

    문제 해석

    1번부터 3번까지 번호가 붙어있는 3개의 방이 있고, 방과 방 사이를 연결하는 길에는 이동하는 걸리는 시간이 표시되어있습니다.

    https://programmers.co.kr/learn/courses/30/lessons/81304

    화살표가 가리키는 방향으로만 이동할 수 있습니다. (단방향 그래프)

    미로에는 함정이 존재하며 함정으로 이동하면 이동한 함정과 연결된 모든 화살표의 방향이 바뀝니다.

    출발지점인 start에서 end로 이동하는데 걸리는 최소 시간을 구하려고 합니다.

     

    문제 풀이 전 설계

    서로 다른 두 방 사이에 직접 연결된 길이 여러 개 존재할 수도 있습니다. (더 작은 값으로만 갱신)

    그래프의 최단거리를 구하는 문제이므로 다익스트라가 생각나는 문제인데 TRAP이라는 함정이 존재하는걸 잘 고려해야 할 것 같습니다.

     

     

    다익스트라 기준으로 탐색하며 해당 노드를 한번만 방문하는 것이 아니라 여러 번 방문할 수 있을 거 같습니다.

    하지만 2번을 초과해서 방문하는 경우는 필요없어 보입니다. (2->3을 반복하면 비용이 증가함)

    (2번인 이유는 위의 그림처럼 1->2를 방문하는 순간 2->4로 갈 수 없어지고 3을 한번 들려야지 다시 방향에 도달할 수 있기 때문에)

     

    문제 풀이하면서

    다익스트라와 비트마스킹을 활용한 문제였습니다.

    신기한 점은 비트 마스킹을 활용하여 해당 트렙이 발동되었는지를 10개의 비트로 체크하고(트랩이 최대 10개이기 때문)

    트렙이 발동된것을 확인함으로써 graph [from][to]로 이동해야 했던 것을 graph [to][from]을 활용하여 해결하였습니다.

    2번만 방문하면 될것같다는 생각까지만 가고 이것을 비트 마스킹을 활용한 방문 체크 + 트랩 체크까지 생각을 확장하지 못했던 것 같습니다.

     

    코드

    import java.util.*;
    
    class Solution {
        
        //최대크기가 1000이고 index로 쓰기위해 1001
        private final static int MAX_N = 1001;
        private final static int INF = Integer.MAX_VALUE;
        static int[][] graph = new int[MAX_N][MAX_N];
        
        int dijkstra(int n, int src, int dst, int[] traps){
            //첫번째 인자가 가중치
            PriorityQueue<int[]> pq = new PriorityQueue<>((c1,c2) -> c1[0] - c2[0]);
            //Trap이 10개이기때문에 10개bit 사용
            boolean[][] visited = new boolean[MAX_N][1 << 10];
            pq.add(new int[]{0, src, 0});
            
            while(!pq.isEmpty()){
                int[] curr = pq.poll();
                int weight = curr[0];
                int index = curr[1];
                int state = curr[2];
                //목적지 도착
                if(index == dst) return weight;
                //방문체크
                if(visited[index][state]) continue;
                visited[index][state] = true;
                
                boolean currTrapped = false;
                HashMap<Integer, Boolean> trapped = new HashMap<>();
                for(int i=0; i< traps.length; i++){
                    int bit = 1 << i;
                    //현재 함정체크가 되어있음
                    if((state & bit) != 0){
                        //현재 함정체크가 되어잇는데 또 방문했음
                        if(traps[i] == index){
                            //비트를 꺼줘야 함
                            state &= ~bit;
                        } else{
                            trapped.put(traps[i],true);
                        }
                    } else {
                    //현재 함정체크가 되어있지 않음
                        if(traps[i] == index){
    			//함정체크를 위한 해당 비트를 켜줌
                            state |= bit;
                            trapped.put(traps[i], true);
                            currTrapped = true;
                        }
                    }
                }
                
                for(int v=1; v<=n; v++){
                    if(v == index) continue;            
                    boolean nextTrapped = trapped.containsKey(v) ? true : false;
                    if(currTrapped == nextTrapped){
                        if(graph[index][v] != INF){
                            pq.add(new int[]{weight + graph[index][v], v, state});
                        }
                    } else{
                        if(graph[v][index] != INF)
                            pq.add(new int[]{weight + graph[v][index], v , state});
                    }
                }
                
                
            }
            return INF;
        }
        
        public int solution(int n, int start, int end, int[][] roads, int[] traps) {
            
            //그래프 INF로 초기화
            for(int i= 1; i <= n; i++){
                for(int j=1; j<=n; j++){
                    if(i==j) graph[i][j] = 0;
                    else graph[i][j] = INF;
                }
            }
            
            //그래프 설정
            for(int[] data : roads){
                int from = data[0], to = data[1], weight = data[2];
                if(weight < graph[from][to])
                    graph[from][to] = weight;
            }
            
            
            int answer = dijkstra(n, start, end, traps);
            return answer;
        }
    }

     

    출처

    https://www.youtube.com/watch?v=B1CjIauForM 

     

    댓글

Designed by Tistory.