머리말
문제를 보고, 아 negative cycle 찾는 문제이구나 싶었다.
그래프에서 최단 경로를 탐색하는 방법 중 다익스트라와 벨만 포드가 있는데,
다익스트라는 Greedy
알고리즘이기 때문에 반드시 간선들이 non-negative weights
을 만족해야 한다.
한편, 벨만 포드는 Dynamic Programming
알고리즘으로 negative weights
를 가져도 정상적으로 동작한다!
접근 방법
- edge relaxation을 N-1번 수행한다.
- 그때 만들어진 distance 배열은 최단 경로이다.
- edge relaxation을 N번째 수행했을 때, 더 짧은 경로를 발견한다면 negative weight cycle이 존재한다는 결론!
이슈 사항
1. 시간 초과
문제에서 시작 정점을 주지 않아, 모든 정점에 대하여 시도하였더니 시간 초과가 발생하였다.
결론은 한 정점에서만 시작해도 된다.
벨만 포드 알고리즘에서 한 정점에서부터 다른 정점의 최단 경로를 파악하려고 했기 때문에 방문했던 노드를 다시 방문하지 않으려고 dist[s] != INF
라는 조건을 주었다. 하지만 이 문제의 경우 최단 경로를 파악하기 위함이 아닌, just 음수 사이클을 판단하면 된다. (결론적으로 dist 배열은 최단 경로를 저장하는 배열은 아님)
2. 맞왜틀?
처음에 무한대를 float('inf')
로 설정하였더니 틀렸다. 대신 int(1e9)
로 잡았더니 성공했다.
이것은 dist[s] != INF
를 해주지 않았기 때문에 무한대 + 무한대
의 계산도 진행된다.
이 과정에서 overflow
가 발생할 여지가 충분하므로 잘못된 계산 결과가 나온다.
코드
import sys
input=sys.stdin.readline
INF = int(1e9)
def bellman_ford(start):
dist = [INF] * (n + 1)
dist[start] = 0
# n-1 (vertex개수-1) 번 반복
for i in range(n):
for j in range(len(edges)):
s, e, t = map(int,edges[j])
if dist[e] > dist[s] + t:
dist[e] = dist[s] + t
if i == n-1: # n번째에도 존재한다면 음의 cycle 존재
return True
return False
tc = int(input())
for _ in range(tc):
n,m,w = map(int,input().split())
edges=[]
for _ in range(m):
s,e,t=map(int,input().split())
edges.append([s, e, t])
edges.append([e, s, t])
for _ in range(w):
s,e,t=map(int,input().split())
edges.append([s, e, -t])
print('YES' if bellman_ford(1) else 'NO')
더 읽을거리
'Algorithm' 카테고리의 다른 글
[Python] 구름LEVEL : 개미와 진딧물 (0) | 2022.11.01 |
---|---|
[Python] 백준 3190 : 뱀 (implementation) (2) | 2022.10.07 |
[Python] 백준 16500 : 문자열 판별 (dp) (0) | 2022.07.19 |
[Python] 백준 12865 : 평범한 배낭 (0/1 knapsack problem) (0) | 2022.07.09 |
[Python] 프로그래머스 : 뉴스 클러스터링 (0) | 2022.07.07 |