https://www.acmicpc.net/problem/1956
접근 방법: 플로이드-워셜 알고리즘
- 주어진 그래프의 모든 노드에서 자기자신으로 이어지는 경로 중 최단 경로를 찾는 문제이므로 플로이드-워셜 알고리즘으로 풀 수 있다.
- 보통의 경우 자기 자신으로 돌아오는 루트를 계산에서 제외하기 위해 초기값을 0으로 잡고 시작하지만, 이를 0으로 잡지 않고 무한대로 준다면 자기 자신으로 돌아오는 경로에 대해서도 추적이 가능하다.
- 테스트케이스의 최대 노드 갯수도 400개 정도로 적게 잡혀있으므로 충분히 시간 안에 돌릴 수 있을 것이다.
코드
import sys
from collections import defaultdict
INF = int(1e9)
input = sys.stdin.readline
V, E = map(int, input().split())
graph = defaultdict(list)
for _ in range(E):
u, v, w = map(int, input().split())
graph[u].append((v, w))
def floyd_warshall(graph, V):
dist = [[INF] * (V + 1) for _ in range(V + 1)]
for start, adjs in graph.items():
for adj, d in adjs:
dist[start][adj] = d
for k in range(1, V + 1):
for a in range(1, V + 1):
for b in range(1, V + 1):
dist[a][b] = min(dist[a][b], dist[a][k] + dist[k][b])
return dist
dist = floyd_warshall(graph, V)
cycle = min([dist[i][i] for i in range(1, V + 1)])
print(cycle) if cycle != int(1e9) else print(-1)
접근 방법: 다익스트라 알고리즘
- 다익스트라 알고리즘도 특정 노드에서 다른 노드로 이어지는 최단 경로를 찾는 알고리즘이므로 사용할 수 있을 것 같았다.
- 다만, 다익스트라 알고리즘은 주어진 특정한 노드에서만 탐색하므로 노드의 갯수만큼 반복해야 최소길이 사이클을 찾을 수 있을것이다.
코드
import heapq
import sys
from collections import defaultdict
INF = int(1e9)
input = sys.stdin.readline
V, E = map(int, input().split())
graph = defaultdict(list)
for _ in range(E):
u, v, w = map(int, input().split())
graph[u].append((v, w))
def dijkstra(graph, start):
dist = defaultdict(lambda: int(1e9))
pq = [(0, start)]
visited = set()
while pq:
acc, cur = heapq.heappop(pq)
if acc > 0 and cur == start:
return acc
if cur in visited:
continue
visited.add(cur)
for adj, d in graph[cur]:
cost = acc + d
if cost < dist[adj]:
dist[adj] = cost
heapq.heappush(pq, (cost, adj))
return int(1e9)
cycle = int(1e9)
for i in range(1, V + 1):
cycle = min(cycle, dijkstra(graph, i))
print(cycle) if cycle != int(1e9) else print(-1)
- 전체 노드만큼 반복문을 돌면서 다익스트라 알고리즘을 적용시켰는데, 시간초과가 되었다.
추가
- 플로이드-워셜 알고리즘은 시간복잡도가 O(V3)이다. 여러 글들을 찾아보니 노드의 갯수가 수백단위를 넘어서면 백준이나 리트코드같이 런타임을 중요하게 체크하는 환경에서는 사용하기 힘들다고 한다.