[2022 KAKAO TECH INTERNSHIP] 등산코스 정하기

최민길(Gale)·2023년 3월 6일
1

알고리즘

목록 보기
50/172

문제 링크 : https://school.programmers.co.kr/learn/courses/30/lessons/118669

[이 문제는 프로그래머스에서 푼 문제입니다.]
이 문제는 우선순위 큐와 Hash 클래스들을 이용하여 풀 수 있습니다. 이 문제는 복잡해보이는 문제를 단순화시키면 좀 더 이해하기 쉽습니다. intensity의 경우 출발점에서 목적지까지 이동하는 도중 절대로 감소하지 않습니다. 따라서 문제에서 구하고자 하는 intensity가 최소가 되는 등산 코스는 각 위치 별 intensity를 이동하면서 계속 계산해준 후 목적지에 도착했을 때 여러 경로 중 가장 작은 값을 출력하면 됩니다.

이 때 intensity를 최소로 하려면 여러 경로 중 가장 가중치가 적은 경로로 이동해야 합니다. 이는 우선순위 큐를 이용하여 원소들을 정렬시켜 poll() 시 가장 작은 값이 나오도록 진행합니다. 여기서 주의할 점은 intensity가 같은 경우 번호가 더 작은 코스를 리턴해야 하니 이 부분도 같이 정렬 기준에 포함시키면 되겠습니다.

다음은 코드입니다.

import java.util.*;

class Solution {
    public int[] solution(int n, int[][] paths, int[] gates, int[] summits) {
        // dp[i] = i번 노드에서의 최소 intensity
        int[] intensities = new int[n+1];
        // 최솟값이 저장되어야 하므로 최댓값으로 초기화
        Arrays.fill(intensities, Integer.MAX_VALUE);

        // 현재 노드를 이동, PQ를 사용하여 최솟값을 향하도록
        PriorityQueue<Graph> map = new PriorityQueue<>();
        // 지나온 노드 체크
        HashSet<Integer> check = new HashSet<>();
        // 정상 데이터 (탐색 시간 단축 위해)
        HashSet<Integer> arrival = new HashSet<>();
        // 노드 별 간선 현황과 가중치 그래프 (탐색 시간 단축 위해 HashMap 사용)
        HashMap<Integer, ArrayList<Graph>> graph = new HashMap<>();

        Graph answer = new Graph(-1,-1,Integer.MAX_VALUE);

        // 그래프 생성
        for(int i=0;i<paths.length;i++){
            int start = paths[i][0];
            int arrive = paths[i][1];
            int time = paths[i][2];

            Graph g1 = new Graph(start,arrive,time);
            Graph g2 = new Graph(arrive,start,time);

            // start 또는 arrive 노드가 초기화되지 않았다면 초기화
            if(!graph.containsKey(start)) graph.put(start,new ArrayList<>());
            if(!graph.containsKey(arrive)) graph.put(arrive,new ArrayList<>());

            // 값 추가
            graph.get(start).add(g1);
            graph.get(arrive).add(g2);
        }

        // 정상 데이터 추가
        for(int i=0;i<summits.length;i++) arrival.add(summits[i]);

        // 출입구 데이터 추가 (HashSet 이용)
        for(int i=0;i<gates.length;i++){
            // 출발 지점이므로 map에 추가
            map.addAll(graph.get(gates[i]));
            // 지나왔으므로 check
            check.add(gates[i]);
            // 출발 지점이므로 intensity가 존재하지 않아 0 추가
            intensities[gates[i]] = 0;
        }

        // 현재 모든 출입구를 탐색
        while (!map.isEmpty()){
            Graph curr = map.poll();

            // 만약 현재 노드가 이미 방문한 노드라면 패스
            if(check.contains(curr.to)) continue;

            // intensity는 지금까지 지나온 intensity와 현재 간선의 가중치 중 최댓값
            int intensity = Math.max(intensities[curr.from], curr.weight);
            // 만약 현재 노드의 초기 intensity가 지금까지 지나온 intensity보다 크다면 지나온 값으로 변경 (최솟값 세팅)
            if(intensity < intensities[curr.to]) intensities[curr.to] = intensity;

            // 만약 현재 노드가 정상이라면 answer값과 비교하여 더 작은 값 넣기
            if(arrival.contains(curr.to)){
                curr = new Graph(0, curr.to, intensity);

                // 비교 1. 더 작은 intensity
                // 비교 2. 더 작은 노드(같은 intensity일 경우)
                if(answer.compareTo(curr) >0) answer = curr;
            }
            // 정상이 아니라면 map에 추가 후 check
            else{
                map.addAll(graph.get(curr.to));
                check.add(curr.to);
            }

        }

        return new int[]{answer.to,answer.weight};
    }
}

class Graph implements Comparable<Graph> {
    int from, to, weight;

    Graph(int from, int to, int weight) {
        this.from = from;
        this.to = to;
        this.weight = weight;
    }

    @Override
    // 가중치가 낮은 노드로 정렬, 같은 가중치일 경우 노드의 오름차순으로 정렬
    public int compareTo(Graph o) {
        if (this.weight == o.weight)
            return Integer.compare(this.to, o.to);
        return Integer.compare(this.weight, o.weight);
    }
}

profile
저는 상황에 맞는 최적의 솔루션을 깊고 정확한 개념의 이해를 통한 다양한 방식으로 해결해오면서 지난 3년 동안 신규 서비스를 20만 회원 서비스로 성장시킨 Software Developer 최민길입니다.

0개의 댓글

관련 채용 정보