Home 1504 특정한 최단 경로
Post
Cancel

1504 특정한 최단 경로

문제 링크: 1504번: 특정한 최단 경로

나의 풀이

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
const fs = require("fs");
const inputs = fs.readFileSync("input").toString().split("\r\n");
const [N, M] = inputs[0].split(" ").map((value) => parseInt(value));
const graph = Array.from({ length: N + 1 }, () => []);
const [v1, v2] = inputs[M + 1].split(" ").map((value) => parseInt(value));

for (let i = 1; i <= M; i++) {
  const [from, to, cost] = inputs[i].split(" ").map((value) => parseInt(value));
  graph[from].push([to, cost]);
  graph[to].push([from, cost]);
}

class Heap {
  constructor() {
    this.heap = [];
  }
  get size() {
    return this.heap.length;
  }
}

class MinHeap extends Heap {
  input(value) {
    this.heap.push(value);
    this.bubbleUp();
  }

  bubbleUp(currentIndex = this.size - 1) {
    if (currentIndex < 1) return;

    const currentNode = this.heap[currentIndex];
    const parentIndex = Math.floor((currentIndex - 1) / 2);
    const parentNode = this.heap[parentIndex];

    if (parentNode.cost <= currentNode.cost) return;

    [this.heap[currentIndex], this.heap[parentIndex]] = [
      parentNode,
      currentNode,
    ];
    this.bubbleUp(parentIndex);
  }

  pull() {
    const min = this.heap[0];
    if (this.size === 1) {
      return this.heap.pop();
    }
    this.heap[0] = this.heap.pop();

    this.bubbleDown();
    return min;
  }

  bubbleDown(currentIndex = 0) {
    const leftIndex = currentIndex * 2 + 1;
    const rightIndex = currentIndex * 2 + 2;
    const length = this.size;
    let parentIndex = currentIndex;

    if (
      leftIndex < length &&
      this.heap[leftIndex].cost < this.heap[parentIndex].cost
    ) {
      parentIndex = leftIndex;
    }
    if (
      rightIndex < length &&
      this.heap[rightIndex].cost < this.heap[parentIndex].cost
    ) {
      parentIndex = rightIndex;
    }
    if (parentIndex !== currentIndex) {
      [this.heap[parentIndex], this.heap[currentIndex]] = [
        this.heap[currentIndex],
        this.heap[parentIndex],
      ];
      this.bubbleDown(parentIndex);
    }
  }
}

const djikstra = (start) => {
  const distance = Array.from({ length: N + 1 }, () => Infinity);
  const priorityQ = new MinHeap();
  distance[start] = 0;
  priorityQ.input({ node: start, cost: 0 });

  while (priorityQ.size > 0) {
    const { node: now, cost: nowCost } = priorityQ.pull();

    for (const [next, nextCost] of graph[now]) {
      if (distance[next] <= nowCost + nextCost) continue;
      distance[next] = nowCost + nextCost;
      priorityQ.input({ node: next, cost: distance[next] });
    }
  }
  if (start === v1) {
    return [distance[1], distance[v2], distance[N]];
  }
  return [distance[1], distance[v1], distance[N]];
};

const [start_v1, v1_v2, v1_end] = djikstra(v1);
const [start_v2, v2_v1, v2_end] = djikstra(v2);

const sumV1 = start_v1 + v1_v2 + v2_end;
const sumV2 = start_v2 + v2_v1 + v1_end;

const answer = sumV1 > sumV2 ? sumV2 : sumV1;
if (answer === Infinity) {
  console.log(-1);
} else {
  console.log(answer);
}

이 문제는 v1과 v2를 꼭 지나야 되며, 양방향 그래프이기 때문에 start에서 v1까지의 최솟값과 v1에서 start까지 최솟값이 같음을 활용해서 풀었다.

  1. v1과 v2를 다익스트라 알고리즘을 사용해서 각각 1, vT(T는 v1이면 2, v2면 1), N번까지의 최솟값을 구한다.
  2. 그림과 같이 빨간색과 파란색 각각의 값을 구한다.
  3. 가장 작은 값을 answer에 저장 후 answer가 Infinity라면 -1을 출력하고, 그렇지 않다면 answer 값을 출력한다.

solution

Feedback

처음 문제를 접했을 땐 노드 하나씩 탐색하고 dfs의 메모이제이션을 활용해서 풀 생각이었다. 하지만 계산을 해보니 오래 걸리고 다익스트라 문제가 아닌 거 같아서 이 방법은 포기하게 되었다. 다시 문제를 읽으면서 생각을 해보니 시작 지점과 끝 지점은 고정되어 있고 v1과 v2가 다르다는 것을 알게 되었다. 또한 양방향 그래프라는 점과 같이 생각을 해보니 다익스트라 시작 지점을 v1과 v2로 두 번만 사용하는 것이 어떤가를 생각하게 되었다. 다음 문제풀이는 의외로 간단하게 되어 생각을 조금 깊게 하면 풀 수 있는 문제였던 거 같다.

-- Missing configuration options! --