2021년 08월 21일 TIL

2 minute read

오늘은 알고리즘 문제를 하루종일 풀었다.

간만에 알고리즘 문제를 푸니 굉장히 재미있었다. 오늘 특히 시간을 많이 소요한 문제는,

카카오 인턴십 Level 4문제 미로탈출이었다.

다익스트라 + 비트마스킹 문제였는데, 확실히 비트마스킹 문제에 내가 약하다는 것을 느꼈다.

항상 비트마스크 문제는 뭔가 다른 형태로 해결하려고하다가, 풀리지않아 답안을 확인하고 나서야 아 이런 형태로 풀수도있구나를 깨닫는 것 같다.

package Programmers;

import java.sql.Array;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.PriorityQueue;
import java.util.Queue;
import org.w3c.dom.Node;

public class 미로탈출 {

    /*
        한쪽만 트랩이 활성화되어있는 경우 역방향
        양쪽 다 트랩이 활성화된 경우 정방향
     */
    static List<Node>[] list;
    static List<Node>[] rList;
    static Map<Integer, Integer> bitTrap;
    static int[][] dist;
    static final int INF = (int) 1e9;
    static int answer = INF;

    public static int solution(int n, int start, int end, int[][] roads, int[] traps) {
        list = new ArrayList[n + 1];
        rList = new ArrayList[n + 1];
        for (int i = 1; i <= n; i++) {
            list[i] = new ArrayList<>();
            rList[i] = new ArrayList<>();
        }

        for (int[] road : roads) {
            list[road[0]].add(new Node(road[1], road[2], 0));
            rList[road[1]].add(new Node(road[0], road[2], 0));
        }
        int idx = 1;
        bitTrap = new HashMap<>();
        for (int i = 0; i < traps.length; i++) {
            bitTrap.put(traps[i], 1 << (i + 1));
        }
        dist = new int[n + 1][1 << traps.length + 1];
        for (int i = 1; i <= n; i++) {
            Arrays.fill(dist[i], INF);
        }

        dijk(start, end);
        for (int res : dist[end]) {
            answer = Math.min(res, answer);
        }
        return answer;
    }

    private static void dijk(int start, int end) {
        Queue<Node> que = new PriorityQueue<>();
        que.offer(new Node(start, 0, 0));
        dist[start][0] = 0;

        while (!que.isEmpty()) {
            Node n = que.poll();
            if (n.to == end) {
                break;
            }
            boolean fromActive = false;
            if (bitTrap.containsKey(n.to)) {
                if ((n.status & bitTrap.get(n.to)) == bitTrap.get(n.to)) {
                    fromActive = true;
                }
            }

            boolean toActive = false;
            for (Node next : list[n.to]) {
                int nStatus = n.status;
                if (bitTrap.containsKey(next.to)) {
                    toActive = ((n.status & bitTrap.get(next.to)) != 0);
                    nStatus = bitFlip(toActive, nStatus, bitTrap.get(next.to));

                    if (fromActive & toActive || (!fromActive & !toActive)) {
                        if (dist[next.to][n.status] > n.cost + next.cost) {
                            dist[next.to][n.status] = n.cost + next.cost;
                            que.offer(new Node(next.to, dist[next.to][n.status], nStatus));
                        }
                    }
                } else {
                    if (!fromActive) {
                        if (dist[next.to][n.status] > n.cost + next.cost) {
                            dist[next.to][n.status] = n.cost + next.cost;
                            que.offer(new Node(next.to, dist[next.to][n.status], nStatus));
                        }
                    }
                }
            }

            toActive = false;
            for (Node next : rList[n.to]) {
                int nStatus = n.status;
                if (bitTrap.containsKey(next.to)) {
                    toActive = ((n.status & bitTrap.get(next.to)) != 0);
                    nStatus = bitFlip(toActive, nStatus, bitTrap.get(next.to));

                }
                if (fromActive ^ toActive) {
                    if (dist[next.to][n.status] > n.cost + next.cost) {
                        dist[next.to][n.status] = n.cost + next.cost;
                        que.offer(new Node(next.to, dist[next.to][n.status], nStatus));
                    }
                }
            }


        }
    }

    private static int bitFlip(boolean flag, int now, int node) {
        // 다음 노드가 trap인데 활성화 되어있는 경우
        if (flag) {
            // 1110
            // 0010
            // 1100
            return now ^ node;
        }
        // 다음 노드가 trap인데 활성화 되어있지 않은 경우
        else {
            // 1100
            // 0010
            // 1110
            return now | node;
        }
    }

    static class Node implements Comparable<Node> {

        int to;
        int cost;
        int status;

        public Node(int to, int cost, int status) {
            this.to = to;
            this.cost = cost;
            this.status = status;
        }

        @Override
        public int compareTo(Node o) {
            return this.cost - o.cost;
        }
    }


}

나중에 한번 꼭 다시 풀어봐야할 문제라고 생각한다.

Categories:

Updated: