자료구조 & 알고리즘 & cs/알고리즘
[TIL] 최단 경로 알고리즘 - 벨만 포드 알고리즘
뽀또롱
2023. 5. 19. 14:50
벨만 포드 알고리즘
- 최단 경로 알고리즘 중 하나로 가중치가 음수인 경우 적용 가능하다.
- 다익스트라보다 시간복잡도가 느리다.
- 음수 사이클 존재의 여부를 파악할 수 있다.
관련문제
11657번: 타임머신
첫째 줄에 도시의 개수 N (1 ≤ N ≤ 500), 버스 노선의 개수 M (1 ≤ M ≤ 6,000)이 주어진다. 둘째 줄부터 M개의 줄에는 버스 노선의 정보 A, B, C (1 ≤ A, B ≤ N, -10,000 ≤ C ≤ 10,000)가 주어진다.
www.acmicpc.net
처음 문제를 접근 할 때 벨만 포드 알고리즘을 몰랐기 때문에
다익스트라 알고리즘으로 접근하였다.
3개의 테스트 케이스를 분석한 뒤에
나름대로(?)
가중치가 음수인 경우를 따로 분리하여 코드를 짰다.
음수인 경우만 체크했을 때에는 12%에서 오답이 떴고
음수의 절댓값까지 체크했을 때에는 40%에서 오답이 떴다.
import sys
import math
import heapq
INF = int(1e9)
input= sys.stdin.readline
n,m = map(int, input().split())
bus=[[] for _ in range(n+1)]
for _ in range(m):
a,b,c = map(int, input().split())
bus[a].append((c,b))
def dijkstra(start):
dist=[INF]*(n+1)
dist[start] = 0
q=[]
heapq.heappush(q, (0,start))
while q:
time , city = heapq.heappop(q)
if dist[city] < time:
continue
for time2, next in bus[city]:
total = time2+time
if dist[next] > total:
if total <0 :
return -1
dist[next] = total
heapq.heappush(q, (total, next))
return dist
if n ==1 and b==1 and c>=0:
print(c)
else:
rst = dijkstra(1)
if rst == -1:
print(rst)
else:
for i in range(2, len(rst)):
if rst[i] ==INF:
print(-1)
else:
print(rst[i])
테스트 케이스는 다 통과했지만 계속 실패를 했고
결국 풀이를 찾아보며 음수 가중치의 순환이 있을 경우
벨만 포드 알고리즘을 사용할 수 있다는 것을 알고
다시 코드를 짜 보았다.
import sys
import math
import heapq
INF = int(1e9)
input= sys.stdin.readline
# 벨만포드 알고리즘
def bf(start):
dist[start] = 0
for i in range(n):
for j in range(m):
cur = edges[j][0]
next = edges[j][1]
cost = edges[j][2]
if dist[cur] != INF and dist[next] > dist[cur]+cost:
dist[next] = dist[cur] +cost
if i == n-1:
return True
return False
n,m = map(int, input().split())
dist=[INF]*(n+1)
edges=[]
for _ in range(m):
a,b,c = map(int, input().split())
edges.append((a,b,c))
cycle = bf(1)
if cycle:
print(-1)
else:
for i in range(2,n+1):
if dist[i] == INF:
print(-1)
else:
print(dist[i])
벨만 포드 알고리즘은 시작 정점에서 다른 모든 정점까지 최단거리를구한다.
만약 그래프 정점의 개수가 n개라면 시작 정점에서 다른 특정한 정점까지 도달하는데 거쳐가는 최대 간선의 개수는
n-1개이기 때문에 n번째에 최단거리 값이 갱신된다면 사이클이 존재함으로 판단할 수 있음을 이용한다.
따라서 정점의 개수 만큼 모든 간선을 고려하여 최단거리를 갱신하면서
사이클이 존재할 경우 False를 리턴하게 하였다.
728x90