๋ณธ๋ฌธ ๋ฐ”๋กœ๊ฐ€๊ธฐ
๐Ÿ”Ž Algorithm/๐Ÿ“ ๊ฐœ๋… ์ •๋ฆฌ

[๊ฐœ๋… ์ •๋ฆฌ] ์ตœ๋‹จ ๊ฑฐ๋ฆฌ ์•Œ๊ณ ๋ฆฌ์ฆ˜ - ๋‹ค์ต์ŠคํŠธ๋ผ

by Seongpyo Hong 2021. 3. 22.

๊ฐ€์ค‘์น˜๊ฐ€ ์—†๋Š” ๊ทธ๋ž˜ํ”„์˜ ์ตœ๋‹จ๊ฑฐ๋ฆฌ ๋ฌธ์ œ๋Š” ๋Œ€๋ถ€๋ถ„ BFS๋กœ ํ•ด๊ฒฐํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ํ•˜์ง€๋งŒ, ๊ฐ„์„ ์— ๊ฐ€์ค‘์น˜๊ฐ€ ์กด์žฌํ•œ๋‹ค๋ฉด BFS๊ฐ€ ์•„๋‹Œ ์ตœ๋‹จ๊ฑฐ๋ฆฌ ์•Œ๊ณ ๋ฆฌ์ฆ˜์„ ํ†ตํ•ด ์ ‘๊ทผํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ์ผ๋ฐ˜์ ์œผ๋กœ ๊ฐ€์ค‘์น˜ ๊ทธ๋ž˜ํ”„์˜ ์ตœ๋‹จ๊ฑฐ๋ฆฌ ๋ฌธ์ œ๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™์€ ์œ ํ˜•์ด ์กด์žฌํ•ฉ๋‹ˆ๋‹ค.

  1. ๋‘ ์ •์  ๊ฐ„์˜ ์ตœ๋‹จ ๊ฑฐ๋ฆฌ๋ฅผ ๊ตฌํ•˜๋Š” ๋ฌธ์ œ
  2. ํ•˜๋‚˜์˜ ์ •์ ์—์„œ ๋‹ค๋ฅธ ๋ชจ๋“  ์ •์ ๊ณผ์˜ ์ตœ๋‹จ๊ฑฐ๋ฆฌ๋ฅผ ๊ตฌํ•˜๋Š” ๋ฌธ์ œ
  3. ํ•˜๋‚˜์˜ ์ •์ ์œผ๋กœ ๊ฐ€๋Š” ๋ชจ๋“  ์ตœ๋‹จ ๊ฒฝ๋กœ๋ฅผ ๊ตฌํ•˜๋Š” ๋ฌธ์ œ
  4. ์ •์  ๊ฐ„์˜ ๋ชจ๋“  ์ตœ๋‹จ ๊ฒฝ๋กœ๋ฅผ ๊ตฌํ•˜๋Š” ๋ฌธ์ œ - ํ”Œ๋กœ์ด๋“œ-์™€์ƒฌ

์ €๋ฒˆ ๊ธ€์—์„œ๋Š” 4๋ฒˆ ์œ ํ˜•์„ ํ•ด๊ฒฐํ•˜๊ธฐ ์œ„ํ•œ ํ”Œ๋กœ์ด๋“œ-์™€์ƒฌ ์•Œ๊ณ ๋ฆฌ์ฆ˜์— ๋Œ€ํ•ด ์•Œ์•„๋ณด์•˜์Šต๋‹ˆ๋‹ค. ์ด๋ฒˆ ๊ธ€์—์„œ๋Š” 2๋ฒˆ ์œ ํ˜•์„ ํ•ด๊ฒฐํ•  ์ˆ˜ ์žˆ๋Š” ๋‹ค์ต์ŠคํŠธ๋ผ ์•Œ๊ณ ๋ฆฌ์ฆ˜์— ๋Œ€ํ•ด์„œ ์•Œ์•„๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.


๋‹ค์ต์ŠคํŠธ๋ผ ์•Œ๊ณ ๋ฆฌ์ฆ˜์€ ๊ฐ„๋‹จํ•˜๊ฒŒ ์„ค๋ช…ํ•˜๋ฉด ์‹œ์ž‘ ์ •์ ์—์„œ ๊ฑฐ๋ฆฌ๊ฐ€ ์ตœ์†Œ์ธ ์ •์ ์„ ์„ ํƒํ•ด ๋‚˜๊ฐ€๋ฉฐ ์ตœ๋‹จ๊ฑฐ๋ฆฌ๋Š” ๊ตฌํ•˜๋Š” ๋ฐฉ์‹์ž…๋‹ˆ๋‹ค. ํ•ด๋‹น ๊ณผ์ •์„ ๊ฐ„๋‹จํ•œ ์ˆ˜๋„์ฝ”๋“œ๋กœ ๋‚˜ํƒ€๋‚ด๋ฉด ๊ฐ™์Šต๋‹ˆ๋‹ค.

V -> ์ •์ ์˜ ๊ฐœ์ˆ˜
Start -> ์‹œ์ž‘ ์ •์ 
Adjacency -> ์ธ์ ‘ํ–‰๋ ฌ or ์ธ์ ‘ ๋ฆฌ์ŠคํŠธ
Distance -> ์‹œ์ž‘ ์ •์ ๋ถ€ํ„ฐ ๊ฐ ์ •์ ๊ฐ„์˜ ์ตœ๋‹จ๊ฑฐ๋ฆฌ
Visited -> ์ตœ๋‹จ๊ฑฐ๋ฆฌ๊ฐ€ ๊ฐฑ์‹ ๋˜์—ˆ๋Š”์ง€ ์ฒดํฌ

for i in (1 to V) :
	Distance[i] = Adjacency[Start][i]

for ๋ชจ๋“  ์ •์ ์˜ ์ตœ๋‹จ๊ฑฐ๋ฆฌ๋ฅผ ๊ฐฑ์‹ ํ–ˆ์„ ๊ฒฝ์šฐ :	
	update_vertex = Distance ์ค‘ ์ตœ์†Œ๊ฐ’์„ ๊ฐ€์ง€๋Š” ์ •์ 
	visited[i] = true;

	for adj_vertex in update_vertex์˜ ์ธ์ ‘ ์ •์  :
		Distance[adj_vertex] = Min(Distance[adj_vertext], 
        			Distance[update_vertex] + Adjacency[update_vertex][adj_vertex][])

Distance ๋ฐฐ์—ด์€ ์‹œ์ž‘ ์ •์ (Start)๋กœ๋ถ€ํ„ฐ ๊ฐ ์ •์ ๊นŒ์ง€์˜ ์ตœ๋‹จ๊ฑฐ๋ฆฌ๋ฅผ ์œ ์ง€ํ•˜๋Š” ๋ฐฐ์—ด์ž…๋‹ˆ๋‹ค. ๋จผ์ € ์ธ์ ‘ํ–‰๋ ฌ์˜ ์ •๋ณด๋ฅผ ํ†ตํ•ด ํ•ด๋‹น ๋ฐฐ์—ด์„ ์ดˆ๊ธฐํ™”ํ•ด์ค๋‹ˆ๋‹ค. ์ดํ›„ ๋ชจ๋“  ์ •์ ์— ๋Œ€ํ•ด ์ตœ๋‹จ ๊ฑฐ๋ฆฌ๋ฅผ ๊ฐฑ์‹ ํ•˜๋Š” ์ž‘์—…์„ ์ง„ํ–‰ํ•ฉ๋‹ˆ๋‹ค. ์ด ๊ณผ์ •์€ ๋‹ค์Œ๊ณผ ๊ฐ™์€ ๊ณผ์ •์„ ๊ฑฐ์น˜๊ฒŒ ๋ฉ๋‹ˆ๋‹ค.

  • ํ˜„์žฌ ๋ฐฉ๋ฌธํ•œ ์ •์ ๋“ค(visited = true)๊ณผ ๊ฐ€์žฅ ๊ฐ€๊นŒ์šด ๊ฑฐ๋ฆฌ์— ์žˆ๋Š” ์ •์ ์„ ์„ ํƒํ•ฉ๋‹ˆ๋‹ค. => update_vertex
  • ํ•ด๋‹น ์ •์ ์„ ๋ฐฉ๋ฌธ ์ฒดํฌํ•ฉ๋‹ˆ๋‹ค.
  • ํ•ด๋‹น ์ •์ (update_vertex)์˜ ์ธ์ ‘ ์ •์ (adj_vertex)์„ ์ˆœํšŒํ•˜๋ฉด์„œ update_vertex๋ฅผ ๊ฑฐ์ณ์„œ adj_vertex๋กœ ๊ฐ€๋Š” ๊ฑฐ๋ฆฌ๊ฐ€ ๋” ๊ฐ€๊น๋‹ค๋ฉด Distance[adj_vertex]๋ฅผ ํ•ด๋‹น ๊ฐ’์œผ๋กœ ๊ฐฑ์‹ ํ•ฉ๋‹ˆ๋‹ค.

์œ„์˜ ๊ณผ์ •์„ ๋ชจ๋“  ์ •์ ์ด ๋ฐฉ๋ฌธ๋  ๋•Œ๊นŒ์ง€ ๋ฐ˜๋ณตํ•˜๋ฉด ์‹œ์ž‘ ์ •์ ๋ถ€ํ„ฐ ๋ชจ๋“  ์ •์ ๊ณผ์˜ ์ตœ๋‹จ๊ฑฐ๋ฆฌ๋ฅผ ์ €์žฅํ•˜๊ณ  ์žˆ๋Š” Distance ๋ฐฐ์—ด์„ ๊ตฌํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.


 

๋ฐฑ์ค€์—์„œ ๋‹ค์ต์ŠคํŠธ๋ผ ๊ธฐ๋ณธ๋ฌธ์ œ์ธ 1753. ์ตœ๋‹จ๊ฒฝ๋กœ ๋ฌธ์ œ๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค.

 

์œ„์˜ ์ˆ˜๋„์ฝ”๋“œ๋ฅผ ์ด์šฉํ•ด Java๋กœ ๊ตฌํ˜„ํ•œ ์ •๋‹ต์€ ๋‹ค์Œ๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค.

public class Solution1753 {
    static final int INF = 10 * 20001;
    static BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
    static HashMap<Integer, Integer>[] adj;
    static boolean[] visited;
    static int[] distance;
    static int V, E, start;
    public static void main(String[] args) throws IOException {
        String[] input = br.readLine().split(" ");
        V = Integer.parseInt(input[0]);
        E = Integer.parseInt(input[1]);
        adj = new HashMap[V + 1];
        visited = new boolean[V + 1];
        distance = new int[V + 1];

        start = Integer.parseInt(br.readLine());

        for (int i = 1; i < V + 1; i++) {
            adj[i] = new HashMap<>();
        }

        for (int i = 0; i < E; i++) {
            String[] line = br.readLine().split(" ");
            int src = Integer.parseInt(line[0]);
            int dest = Integer.parseInt(line[1]);
            int weight = Integer.parseInt(line[2]);
            if (adj[src].containsKey(dest) && adj[src].get(dest) > weight) {
                adj[src].put(dest, weight);
            } else if (!adj[src].containsKey(dest)) {
                adj[src].put(dest, weight);
            }
        }

        // init distance
        for (int i = 1; i < V + 1; i++) {
            if (start == i) {
                distance[i] = 0;
                continue;
            }

            if (!adj[start].containsKey(i))
                distance[i] = INF;
            else
                distance[i] = adj[start].get(i);
        }

        djkstra();

        for (int i = 1; i < V + 1; i++) {
            if (distance[i] == INF)
                System.out.println("INF");
            else
                System.out.println(distance[i]);
        }
    }

  private static void djkstra() {
      for (int id = 1; id < V + 1; id++) {
          int idx = -1;
          int minDist = INF;
          for (int i = 1; i < V + 1; i++) {
              if (visited[i] || minDist < distance[i]) continue;
              idx = i;
              minDist = distance[i];
          }

          visited[idx] = true;
          if (minDist == INF) continue;
          for(Integer dest : adj[idx].keySet()) {
              int weight = adj[idx].get(dest);
              if (visited[dest] || distance[dest] <= distance[idx] + weight) continue;
              distance[dest] = distance[idx] + weight;
          }
      }
  }
}

ํ•ด๋‹น ๋ฌธ์ œ๋Š” ์ •์ ์˜ ๊ฐœ์ˆ˜๊ฐ€ 200,000๊ฐœ์ด๊ธฐ ๋•Œ๋ฌธ์— ์ธ์ ‘ ๋ฆฌ์ŠคํŠธ๋กœ ํ‘œํ˜„ํ•˜์˜€์Šต๋‹ˆ๋‹ค. ์—ฌ๊ธฐ์„œ ํ•œ ๊ฐ€์ง€ ๋ฌธ์ œ ์กด์žฌํ•˜๋Š”๋ฐ ์œ„์˜ ์ฝ”๋“œ๋Š” O(V^2)์˜ ์‹œ๊ฐ„๋ณต์žก๋„๋ฅผ ๊ฐ€์ง€๊ฒŒ ์ •์ ์ด ๋งŽ์€ ๊ฒฝ์šฐ์—๋Š” ์‹œ๊ฐ„ ์ดˆ๊ณผ๊ฐ€ ๋ฐœ์ƒํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.


์—ฌ๊ธฐ์„œ ์ตœ์ ํ™” ์‹œํ‚ฌ ์ˆ˜ ์žˆ๋Š” ๋ถ€๋ถ„์€ ํ˜„์žฌ ๋ฐฉ๋ฌธํ•œ ์˜์—ญ๊ณผ ์ตœ๋‹จ๊ฑฐ๋ฆฌ๋ฅผ ๊ฐ–๋Š” ์ •์ ์„ ๊ตฌํ•˜๋Š” ๋ถ€๋ถ„์ž…๋‹ˆ๋‹ค. ๋‹จ์ˆœํžˆ ๋ฐฐ์—ด๋กœ ์ €์žฅํ•˜๋Š” ๊ฒƒ์ด ์•„๋‹Œ ์šฐ์„  ์ˆœ์œ„ ํ๋ฅผ ํ†ตํ•ด ํ•ด๋‹น ๊ณผ์ •์„ ์ˆ˜ํ–‰ํ•œ๋‹ค๋ฉด O(N) => O(logN)์œผ๋กœ ๋‹จ์ถ•ํ•  ์ˆ˜ ์žˆ๊ณ  ์ตœ์ข…์ ์œผ๋กœ O((|E| + |V|) * logV)์˜ ์‹œ๊ฐ„๋ณต์žก๋„๋กœ ์ตœ์ ํ™”๊ฐ€ ๊ฐ€๋Šฅํ•ฉ๋‹ˆ๋‹ค.

์šฐ์„  ์ˆœ์œ„ํ๋ฅผ ํ†ตํ•ด ๊ตฌํ˜„ํ•œ ์ฝ”๋“œ๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค.

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.PriorityQueue;

public class Solution1753 {
    static class Edge implements Comparable<Edge> {
        int id;
        int weight;
        public Edge(int id, int weight) {
            this.id = id;
            this.weight = weight;
        }


        @Override
        public int compareTo(Edge o) {
            return Integer.compare(this.weight, o.weight);
        }
    }
    static final int INF = 10 * 20001;
    static BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
    static ArrayList<Edge>[] adj;
    static boolean[] visited;
    static int[] distance;
    static int V, E, start;
    public static void main(String[] args) throws IOException {
        String[] input = br.readLine().split(" ");
        V = Integer.parseInt(input[0]);
        E = Integer.parseInt(input[1]);
        adj = new ArrayList[V + 1];
        visited = new boolean[V + 1];
        distance = new int[V + 1];

        start = Integer.parseInt(br.readLine());

        for (int i = 1; i < V + 1; i++) {
            adj[i] = new ArrayList<>();
        }

        for (int i = 0; i < E; i++) {
            String[] line = br.readLine().split(" ");
            int src = Integer.parseInt(line[0]);
            int dest = Integer.parseInt(line[1]);
            int weight = Integer.parseInt(line[2]);
            adj[src].add(new Edge(dest, weight));
        }

        // init distance
        for (int i = 1; i < V + 1; i++) {
            if (start == i) {
                distance[i] = 0;
                continue;
            }
            distance[i] = INF;
        }

        djkstra();

        for (int i = 1; i < V + 1; i++) {
            if (distance[i] == INF)
                System.out.println("INF");
            else
                System.out.println(distance[i]);
        }
    }

    private static void djkstra() {
        PriorityQueue<Edge> pq = new PriorityQueue<>();
        pq.add(new Edge(start, 0));
        while(!pq.isEmpty()) {
            Edge cur = pq.poll();

            if (cur.weight > distance[cur.id]) continue;
            for (int i = 0; i < adj[cur.id].size(); i++) {
                Edge next = adj[cur.id].get(i);
                if (distance[next.id] > distance[cur.id] + next.weight) {
                    distance[next.id] = distance[cur.id] + next.weight;
                    pq.add(new Edge(next.id, distance[next.id]));
                }
            }
        }
    }
}

์—ฌ๊ธฐ์„œ ์ฃผ๋ชฉํ•  ๋ถ€๋ถ„์€ ๊ธฐ์กด์˜ visited๋ฅผ ํ†ตํ•ด ๋ฐฉ๋ฌธ์ฒดํฌ๋ฅผ ํ•ด์คฌ๋˜ ๊ฒƒ๊ณผ ๋‹ฌ๋ฆฌ ์šฐ์„  ์ˆœ์œ„ํ๋ฅผ ์‚ฌ์šฉํ•˜๊ฒŒ ๋˜๋ฉด ๊ฑฐ๋ฆฌ๋ฅผ ๊ฐฑ์‹ ํ•œ ํ›„, ํ˜„์žฌ ๊ฑฐ๋ฆฌ๊ฐ€ distance์˜ ๊ฐ’๋ณด๋‹ค ํด ๊ฒฝ์šฐ ๊ฑด๋„ˆ ๋œ€์œผ๋กœ์จ ๋ฐฉ๋ฌธ ์ฒดํฌ๋ฅผ ํ•  ์ˆ˜ ์žˆ๋‹ค๋Š” ์ ์ž…๋‹ˆ๋‹ค. 


์ด๋ฒˆ ๊ธ€์—์„œ๋Š” ํ•œ ์ •์ ์—์„œ ๋‹ค๋ฅธ ๋ชจ๋“  ์ •์ ๊นŒ์ง€์˜ ์ตœ๋‹จ ๊ฑฐ๋ฆฌ๋ฅผ ๊ตฌํ•  ์ˆ˜ ์žˆ๋Š” ๋‹ค์ต์ŠคํŠธ๋ผ ์•Œ๊ณ ๋ฆฌ์ฆ˜์— ๋Œ€ํ•ด์„œ ์•Œ์•„๋ณด์•˜์Šต๋‹ˆ๋‹ค. ์ถ”๊ฐ€๋กœ ์ฝ”๋“œ๋ฅผ ์ž‘์„ฑํ•˜๋ฉฐ ์‰ฝ๊ฒŒ ํ—ท๊ฐˆ๋ฆด ์ˆ˜ ์žˆ๋Š” ๋ถ€๋ถ„๋“ค์— ๋Œ€ํ•ด ์ž˜ ์ •๋ฆฌ๋œ ๊ธ€์ด ์žˆ์–ด์„œ ํ•ด๋‹น ๊ธ€์„ ์ฝ์–ด๋ณด์‹œ๋Š” ๊ฒƒ๋„ ์ถ”์ฒœ๋“œ๋ฆฝ๋‹ˆ๋‹ค.

์ฐธ๊ณ  ์ž๋ฃŒ

www.secmem.org/blog/2019/01/09/wrong-dijkstra/

๋Œ“๊ธ€