벨만 포드의 경우는 음수 가중치가 존재하는 경우에도 적용할 수 있지만 다익스트라는 음수 간선 자체가 존재할 수 없음.
대신 다익스트라는 벨만 포드에 비해 실행 속도가 빠름. (O(VlongV) V: 정점 개수)
음의 가중치 자체가 문제가 되는 것은 아니지만, 음의 값이 누적되는 사이클을 형성하면 문제가 됨.

예를 들어서 노드 ㄱ에서 노드 ㄹ까지의 최단 거리를 구한다고 할 때, 2 → 3 → -6 → 3 → -6 → …의 음의 값이 누적되는 사이클이 형성되며, 이 사이클을 무한히 돌아야 최단 거리가 반환됨.
각 정점들을 차례로 돌아가면서 해당 정점의 간선들을 탐색함.
단, 맨 처음은 시작점부터 탐색함.
그리고 그 간선의 가중치와 시작점에서 정점까지의 거리의 합이 해당 간선이 도달하고자 하는 정점의 기존 거리보다 작으면 업데이트 함.
d[T] ≤ d[S] + w(S, T)
d - 시작점에서 해당 정점의 거리
w - 해당 간선의 가중치
T - 해당 간선이 도달하고자 하는 정점
S - 해당 간선의 시작점

예를 들어서 다음과 같은 노드 5개와 간선 9개가 있다고 하자.
[1번 노드]
1번 노드는 모든 노드와 연결되어 있기 때문에 가중치를 갱신함.
| 0 | -6 | 3 | 9 | 8 | 
|---|
[2번 노드]
2번 노드는 3번 노드와 연결되어 있으며, 1→3의 3보다 1→2→3의 -8이 더 작으므로 가중치를 갱신함.
| 0 | -6 | -8 | 9 | 8 | 
|---|
[3번 노드]
3번 노드는 4번 노드와 5번 노드와 연결되어 있음.
1→4의 9보다 1→2→3→4의 -3이 더 작으므로 가중치를 갱신하며,
1→5의 8보다 1→2→3→5의 -15가 더 작으므로 가중치를 마저 갱신함.
| 0 | -6 | -8 | -3 | -15 | 
|---|
[4번 노드]
4번 노드는 3번 노드와 연결되어 있음.
1→4→3의 5가 -8보다 크므로 갱신하지 않음.
| 0 | -6 | -8 | 9 | 8 | 
|---|
[5번 노드]
5번 노드는 3번 노드와 연결되어 있음.
1→5→3의 -5가 -8보다 크므로 갱신하지 않음.
| 0 | -6 | -8 | 9 | 8 | 
|---|
다음과 같은 과정을 노드 개수 - 1번 반복해야 함.
그리고 추가적으로 음의 사이클의 존재 여부를 파악하고 싶다면 마지막으로 한 번 더 반복하여 총 노드 개수 만큼을 반복하였을 때, 노드 개수 - 1번 했을 때와 값이 달라진다면 음의 사이클이 있는 것으로 판별할 수 있음.
다음의 코드는 백준 1865 웜홀의 코드임.
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.StringTokenizer;
public class Main {
    private static final int INF = 100_000_000;
    private static int n;
    private static int[] dist;
    private static List<Node>[] list;
    public static void main(String[] args) throws IOException {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(System.out));
        int tc = Integer.parseInt(br.readLine());
        while (tc-- > 0) {
            StringTokenizer st = new StringTokenizer(br.readLine());
            n = Integer.parseInt(st.nextToken());
            int m = Integer.parseInt(st.nextToken());
            int w = Integer.parseInt(st.nextToken());
            list = new ArrayList[n+1];
            dist = new int[n+1];
            Arrays.fill(dist, INF);
            for (int i = 1; i <= n; i++) {
                list[i] = new ArrayList<>();
            }
            for (int i = 0; i < m + w; i++) {
                st = new StringTokenizer(br.readLine());
                int from = Integer.parseInt(st.nextToken());
                int to = Integer.parseInt(st.nextToken());
                int dist = Integer.parseInt(st.nextToken());
                if (i < m) {
                    list[from].add(new Node(to, dist));
                    list[to].add(new Node(from, dist));
                } else list[from].add(new Node(to, -dist));
            }
            bw.write(bellmanFord() ? "YES\n" : "NO\n");
        }
        br.close();
        bw.flush();
        bw.close();
    }
    private static boolean bellmanFord() {
        dist[1] = 0;
        for (int i = 1; i < n; i++) { // 노드 개수 - 1번 반복
            for (int j = 1; j < list.length; j++) {
                for (Node nxt : list[j]) {
                    if (dist[nxt.to] > dist[j] + nxt.dist)
                        dist[nxt.to] = dist[j] + nxt.dist;
                }
            }
        }
        for (int i = 1; i < list.length; i++) { // 노드 개수 번째 반복에서 값 비교
            for (Node nxt : list[i]) {
                if (dist[nxt.to] > dist[i] + nxt.dist) return true;
            }
        }
        return false;
    }
}
class Node {
    int to;
    int dist;
    Node(int to, int dist) {
        this.to = to;
        this.dist = dist;
    }
}https://velog.io/@suk13574/알고리즘Java-벨만-포드Bellman-Ford-알고리즘
https://developer-davii.tistory.com/89
https://roytravel.tistory.com/340