문제


방향그래프가 주어지면 주어진 시작점에서 다른 모든 정점으로의 최단 경로를 구하는 프로그램을 작성하시오. 단, 모든 간선의 가중치는 10 이하의 자연수이다.

 

입력


첫째 줄에 정점의 개수 V와 간선의 개수 E가 주어진다. (1≤V≤20,000, 1≤E≤300,000) 모든 정점에는 1부터 V까지 번호가 매겨져 있다고 가정한다. 둘째 줄에는 시작 정점의 번호 K(1≤K≤V)가 주어진다. 셋째 줄부터 E개의 줄에 걸쳐 각 간선을 나타내는 세 개의 정수 (u, v, w)가 순서대로 주어진다. 이는 u에서 v로 가는 가중치 w인 간선이 존재한다는 뜻이다. u와 v는 서로 다르며 w는 10 이하의 자연수이다. 서로 다른 두 정점 사이에 여러 개의 간선이 존재할 수도 있음에 유의한다.

 

출력

 

첫째 줄부터 V개의 줄에 걸쳐, i번째 줄에 i번 정점으로의 최단 경로의 경로값을 출력한다. 시작점 자신은 0으로 출력하고, 경로가 존재하지 않는 경우에는 INF를 출력하면 된다.

예제 입력과 출력

 

 

알고리즘 분류


다익스트라 알고리즘

 

정답

 

import sys
import heapq

input = lambda : sys.stdin.readline().strip()   
INF = sys.maxsize

def Dijkstra(a, K):
    dist = [INF] * len(a)  
    dist[K] = 0

    heap = []
    heapq.heappush(heap, [0, K])
    
    while heap:
        current_dist, here = heapq.heappop(heap)
        for there, length in a[here].items():
            next_dist = dist[here] + length

            if next_dist < dist[there]:
                dist[there] = next_dist
                heapq.heappush(heap, [next_dist, there])

    return dist

V, E = map(int, input().split())
K = int(input())
a = [{} for _ in range(V + 1)]

for i in range(E):
    u, v, w = map(int, input().split())

    if v in a[u]:
        a[u][v] = min(a[u][v], w)
    else:
        a[u][v] = w

dist=Dijkstra(a, K)

for d in dist[1:]:
    print(d if d != INF else "INF")

다익스트라 알고리즘 기본 코드를 이용합니다.

 


백준 알고리즘 1753번 : www.acmicpc.net/problem/1753

 

1753번: 최단경로

첫째 줄에 정점의 개수 V와 간선의 개수 E가 주어진다. (1≤V≤20,000, 1≤E≤300,000) 모든 정점에는 1부터 V까지 번호가 매겨져 있다고 가정한다. 둘째 줄에는 시작 정점의 번호 K(1≤K≤V)가 주어진다.

www.acmicpc.net

 

다익스트라(Dijkstra) 알고리즘

 

다익스트라(Dijkstra) 알고리즘은 특정한 하나의 시작 정점에서 모든 다른 정점까지의 최단 경로를 찾는 탐색 알고리즘입니다.

 

최단 경로는 경로의 길이순으로 구해집니다.

 

경로는 간선으로 주어지는데 이때 간선의 가중치는 문제에서 비용, 거리, 시간 등으로 나타납니다.

 

다익스트라(Dijkstra) 알고리즘의 과정입니다.

1. 하나의 시작 정점을 설정하고 이를 기준으로 각 최소 비용을 배열에 저장합니다.
    바로 갈 수 없는 곳의 값은 INF로 합니다.
2. 방문하지 않은 점 중 가장 비용이 적은 정점을 선택합니다.
3. 해당 정점를 거쳐 특정한 정점으로 가는 경우를 고려하여 최소비용을 변경합니다.
4. 위의 과정을 반복해 최단 경로를 탐색합니다.

 

 

다음과 같은 단방향 그래프가 있으면 정점은 1, 2, 3, 4, 5, 6으로 6개입니다.

간선은 1 → 2, 1 → 3, 1 → 4, 2 → 6, 3 → 4로 5개입니다.

 

다익스트라 알고리즘은 시작점이 있어야 합니다. 1부터 모든 정점까지의 최단 경로를 탐색하겠습니다.

 

Dist는 1부터 각 정점까지의 최단 경로를 담는 배열입니다.

Dist에 1에서 1을 가는 경로는 0이기 때문에 Dist[1]은 0으로 설정해줍니다.

이 외의 값들은 아직 모르기 때문에 최대값을 넣습니다.

 

1에서 각 정점들의 최단 경로를 탐색에 Dist에 있는 값보다 작은 경우 최단 경로를 Dist에 넣습니다.

1에서 2로 가는 경로는 길이가 2이기 때문에 INF보다 적으니 Dist[2]는 2로 바꿔줍니다.

1에서 3로 가는 경로는 길이가 3이기 때문에 INF보다 적으니 Dist[3]는 3로 바꿔줍니다.

1에서 4로 가는 경로는 길이가 6이기 때문에 INF보다 적으니 Dist[4]는 6로 바꿔줍니다.

 

2에서는 1에서 2를 거쳐 6으로 가는 경로의 길이가 6이기 때문에 INF보다 적으니 Dist[6]는 6로 바꿔줍니다.

 

3에서는 1에서 3를 거쳐 4으로 가는 경로의 길이가 4인데 기존에 있던 6(1에서 4로 가는 경로) 보다 적으니 Dist[4]는 4로 바꿔줍니다.

 

4에서는 변경이 없습니다.

 

6에서는 변경이 없습니다.

 

다익스트라 알고리즘이 끝나면 정점 1, 2, 3, 4, 6을 거친 것을 알 수 있습니다.

정점 5를 연결해주는 간선은 없기 때문에 정점 5는 거치지 않았습니다.

 

최종적인 Dist가 1에서 각 정점까지의 최단 경로입니다.

Dist[0] 코드의 편리를 위해 만들었고 실제로는 정점도 없고 거치지 않았기 때문에 제외해야 합니다.

 

위의 예시를 이용한 다익스트라 알고리즘 파이썬 코드입니다.

import heapq
import sys

INF = sys.maxsize

def Dijkstra(adjacent, K):

    dist = [INF] * len(adjacent)   # source로부터의 최소 거리 배열, 무한대로 초기
    
    dist[K] = 0 #시작점에서 시작점으로의 거리는 0으로 설정

    queue = []
    heapq.heappush(queue, [0, K]) #시작점 넣기
    
    while queue:

        # 거리가 제일 작은 노드 선택
        current_dist, here = heapq.heappop(queue)

        # 인접 노드 iteration
        for there, length in adjacent[here].items():
            next_dist = dist[here] + length

            if next_dist < dist[there]:
                dist[there] = next_dist
                heapq.heappush(queue, [next_dist, there])

    return dist

# v는 정점, e는 간선, k는 시작점
V=6
E=5

adjacent=[{}, {2: 2, 3: 3, 4: 6}, {6: 4}, {4: 1}, {}, {}, {}]

dist = Dijkstra(adjacent, 1)

for d in dist[1:]:
    print(d if d != INF else "INF")

 

 

힙(heap) 큐 알고리즘을 이용한 기본 다익스트라 알고리즘 파이썬 코드입니다.

import heapq
import sys

INF = sys.maxsize

def Dijkstra(adjacent, K):

    prev = [-1] * len(adjacent)   # 이전에 거친 것 구하는 배열
    dist = [INF] * len(adjacent)   # K로부터의 최소 거리 배열, INF로 초기화

    dist[K] = 0 #시작점에서 시작점으로의 거리는 0으로 설정

    queue = []
    heapq.heappush(queue, [0, K]) #시작점 넣기
    
    while queue:
	# 거리가 제일 작은 노드 선택
    # current_dist: 현재까지의 거리, here : 지금 위치한 곳의 정점
        current_dist, here = heapq.heappop(queue) 

        for there, length in adjacent[here].items():
            next_dist = dist[here] + length

            if next_dist < dist[there]:
                dist[there] = next_dist
                prev[there] = here
                heapq.heappush(queue, [next_dist, there])

    return dist, prev

# V는 정점 수, E는 간선 수, K는 시작점
V, E = map(int, input().split())
K = int(input())
adjacent = [{} for _ in range(V + 1)]

for i in range(E):
    u, v, w = map(int, input().split())

    #같은 경로의 간선이 주어질 경우 적은 비용의 간선 선택
    if v in adjacent[u]:
        adjacent[u][v] = min(adjacent[u][v], w)
    else:
        adjacent[u][v] = w

dist, prev = Dijkstra(adjacent, 1)

for d in dist[1:]:
    print(d if d != INF else "INF")

 

+ Recent posts