n개의 지점으로 이뤄진 등산 코스는 출발점과 정상인 산봉우리, 등산로로 이뤄져 있다. 각 지점을 지날 때마다
intensity
라 불리는 시간이 소요된다. 출입구 중 한 곳에서 출발하여 산봉우리 중 한 곳만 방문한 뒤 다시 원래 출입구로 돌아오는 등산코드를 선택할 것이다.
즉, 등산코스와 출입구는 처음과 끝에서 한 번만, 산봉우리는 한 번만 포함되어야 한다.
해당 등산코드를 대표하는intensity
는 해당 코스에서 가장 큰intensity
가 된다.
이 규칙을 지키며, 여러 등산 코스 중intensity
가 최소가 되는 등산코스를 정하자.
만일intensity
가 같은 코스가 여러 개일 경우, 그 중 산봉우리 번호가 가장 낮은 등산코스를 선택하자.
n | paths | gates | summits | result |
---|---|---|---|---|
6 | [[1, 2, 3], [2, 3, 5], [2, 4, 2], [2, 5, 4], [3, 4, 4], [4, 5, 3], [4, 6, 1], [5, 6, 1]] | [1, 3] | [5] | [5, 3] |
7 | [[1, 4, 4], [1, 6, 1], [1, 7, 3], [2, 5, 2], [3, 7, 4], [5, 6, 6]] | [1] | [2, 3, 4] | [3, 4] |
n
≤ 50,000n
-1 ≤ paths
의 길이 ≤ 200,000paths
는 [i, j, w]
형태이다.i
번 지점과 j
번 지점을 연결하는 등산로를 의미w
는 두 지점 사이에 소요된 이동 시간w
≤ 10,000,000Dijkstar
알고리즘 사용intensity
가 최소가 되기 때문(1) 노드와 가중치로 이뤄진 Node
클래스 선언
(2) paths
의 각 지점을 경우에 맞게 양방향 혹은 단뱡향으로 저장
등산코스와 출입구는 처음과 끝에서 한 번만, 산봉우리는 한 번만 포함되어야 한다.
조건을 충족시킬 수 있다.(3) BFS
를 위해 모든 출발지를 Queue에 삽입
(4) 현 지점에 도달하기까지 계산된 가장 긴 intensity
와 다음 지점으로 이동시 소요되는 intensity
중 가장 큰 값을 dist
에 저장
※ 결국 문제에서 요구하는 것은 선택된 등산 코스의 가장 긴 intensity
이기 때문에
(5) 다른 등산 코스에서 다음 지점에 도달하기까지 갖게 된 가장 intensity
와 비교
A->C
의 intensity
와 B->C
의 intensity
를 비교intensity
배열을 해당 값으로 저장 :다익스트라
(7) Queue에 다음 지점 삽입
(8) summits
배열 오름차순으로 정렬
※ intensity
가 동일할 경우, 산봉우리가 가장 낮은 코스를 선택해야하기 때문
(9) 산봉우리에 도달할 때까지 가장 긴 intensity
가 intensity[summit]
에 저장되기 때문에, 각 산봉우리 별 가장 짧은 intensity
판별 및 해당 산봉우리 저장
(10) int[]
배열로 반환
import java.util.*;
import java.math.*;
class Solution {
static List<List<Node>> graph;
static final int INF = 10_000_001;
private static class Node {
int e, w;
Node(int e, int w) {
this.e = e;
this.w = w;
}
}
public int[] solution(int n, int[][] paths, int[] gates, int[] summits) {
int[] answer = {};
graph = new ArrayList<>();
for(int i=0;i<n+1;i++) {
graph.add(new ArrayList<>());
}
for(int[] i : paths) {
int start = i[0];
int end = i[1];
int weight = i[2];
if (isGate(start, gates) || isSummit(end, summits)) {
graph.get(start).add(new Node(end, weight));
} else if (isGate(end, gates) || isSummit(start, summits)) {
graph.get(end).add(new Node(start, weight));
} else {
// 일반 등산로일 경우, 양방향
graph.get(start).add(new Node(end, weight));
graph.get(end).add(new Node(start, weight));
}
}
return dijkstra(n, gates, summits);
}
private static int[] dijkstra(int n, int[] gates, int[] summits) {
Queue<Node> queue = new LinkedList<>();
int[] intensity = new int[n+1];
Arrays.fill(intensity, INF);
for(int i: gates) {
queue.add(new Node(i, 0));
intensity[i] = 0;
}
while (!queue.isEmpty()) {
Node curNode = queue.poll();
// 현 노드의 가중치가 계산된 노드의 가중치보다 크다면, 최소 갱신이 안 됨으로 스킵
if (curNode.w > intensity[curNode.e])
continue;
// 연결된 노드 탐색
for(int i=0;i<graph.get(curNode.e).size(); i++) {
Node next = graph.get(curNode.e).get(i);
int dist = Math.max(intensity[curNode.e], next.w);
if (intensity[next.e] > dist) {
intensity[next.e] = dist;
queue.add(new Node(next.e, dist));
}
}
}
int summitIndex = INF;
int lowerWeight = INF;
// intensity 동일할 경우, 산봉우리 번호가 가장 낮은 코스 선택
Arrays.sort(summits);
for(int summit : summits) {
if (intensity[summit] < lowerWeight) {
lowerWeight = intensity[summit];
summitIndex = summit;
}
}
return new int[]{summitIndex, lowerWeight};
}
private static boolean isSummit(int x, int[] summits) {
for(int s : summits) {
if (s == x)
return true;
}
return false;
}
private static boolean isGate(int x, int[] gates) {
for(int g : gates) {
if (g == x)
return true;
}
return false;
}
}
Dijkstra
를 시도하려 했으나 미숙하여 해결하지 못 했다.Dijkstra
이론만 공부하고, 처음 접해본 문제여서 그런지 감은 잡히는데 어떻게 풀어나갈지 해답을 찾지 못 했다. 그래서 여러 시도에 도전하기보단 이 문제를 통해 다익스트라의 흐름과 응용 방식을 터득하고자 했다.
그래서 4일차 TIL인데 5일차에 쓰고 있다..하하..
처음 접했을 때 어려웠고, 다른 분들 풀이를 봤을 땐 더 어려웠다. 내용을 정리하고, 하나하나 대입하면서 여러 시도 끝에 80% 정도는 이해했지만 완벽히 이해하진 못 했다.
다음에 다시 풀어봐야겠다.
많이 헤맸던 문제였는데 풀이 잘 보구 갑니다!