Algorithm & Data Structures/BOJ

b.11657 νƒ€μž„λ¨Έμ‹ 

Geisha 2025. 3. 20. 23:07

 

https://www.acmicpc.net/problem/11657

 

 

 

πŸ“Œ μžλ°”(Java)둜 ν‘ΈλŠ” νƒ€μž„λ¨Έμ‹  문제 - λ°±μ€€ 11657 ⏳

 


πŸ”Ž 문제 κ°œμš”

 

λ°±μ€€ 11657번 - νƒ€μž„λ¨Έμ‹  λ¬Έμ œμž…λ‹ˆλ‹€.

N개의 λ„μ‹œμ™€ M개의 λ²„μŠ€ 노선이 μ£Όμ–΄μ§ˆ λ•Œ,

“1번 λ„μ‹œμ—μ„œ λ‹€λ₯Έ λͺ¨λ“  λ„μ‹œλ‘œ κ°€λŠ” μ΅œλ‹¨ μ‹œκ°„” 을 κ΅¬ν•˜λŠ” λ¬Έμ œμž…λ‹ˆλ‹€.

πŸ•° 단, 음수 κ°€μ€‘μΉ˜(μ‹œκ°„μ΄ κ°μ†Œν•˜λŠ” 경우)도 μ‘΄μž¬ν•  수 있으며, 음수 사이클 μ—¬λΆ€λ₯Ό νŒλ³„ν•΄μ•Ό ν•©λ‹ˆλ‹€.

 



πŸ’‘ 예제 μž…λ ₯

3 4
1 2 4
1 3 3
2 3 -2
3 1 -1

πŸ’‘ 예제 좜λ ₯

4
3
-1

➑ 1번 λ„μ‹œμ—μ„œ 각각 2번, 3번으둜 κ°€λŠ” μ΅œλ‹¨ 거리 좜λ ₯ (도달 λΆˆκ°€λŠ₯ μ‹œ -1)

 



πŸ›  μ•Œκ³ λ¦¬μ¦˜ μ ‘κ·Ό 방식

 

이 문제λ₯Ό ν•΄κ²°ν•˜κΈ° μœ„ν•΄ 벨만-ν¬λ“œ μ•Œκ³ λ¦¬μ¦˜(Bellman-Ford Algorithm) 을 μ‚¬μš©ν•©λ‹ˆλ‹€.

 

✏️ μ£Όμš” κ³ λ € 사항

 

βœ” λ‹€μ΅μŠ€νŠΈλΌ μ•Œκ³ λ¦¬μ¦˜μ„ μ‚¬μš©ν•  수 μ—†λŠ” 이유 → 음수 κ°€μ€‘μΉ˜κ°€ 쑴재

βœ” 벨만-ν¬λ“œ μ•Œκ³ λ¦¬μ¦˜μ„ μ‚¬μš©ν•˜μ—¬ μ΅œλ‹¨ 경둜 계산 (O(NM))

βœ” N-1번 λ°˜λ³΅ν•˜μ—¬ λͺ¨λ“  λ…Έλ“œμ˜ μ΅œλ‹¨ 거리λ₯Ό κ°±μ‹ 

βœ” Nλ²ˆμ§Έμ—λ„ 값이 κ°±μ‹ λ˜λ©΄, 음수 사이클이 μ‘΄μž¬ν•˜λŠ” 것

 



πŸ”Ή Java μ½”λ“œ ν•΄μ„€

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.StringTokenizer;

public class b11657 {

    static class Node {
        int start, end, time;

        public Node(int start, int end, int time) {
            this.start = start;
            this.end = end;
            this.time = time;
        }
    }

    static int N, M;
    static ArrayList<Node> edges;
    static long[] dist; // long νƒ€μž… μ‚¬μš© (μ˜€λ²„ν”Œλ‘œμš° λ°©μ§€)
    static final long INF = Long.MAX_VALUE;

    public static void main(String[] args) throws IOException {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        StringTokenizer st = new StringTokenizer(br.readLine());

        N = Integer.parseInt(st.nextToken());
        M = Integer.parseInt(st.nextToken());

        edges = new ArrayList<>();
        dist = new long[N + 1];
        Arrays.fill(dist, INF);
        dist[1] = 0; // μ‹œμž‘μ  거리 0

        // κ°„μ„  정보 μž…λ ₯
        for (int i = 0; i < M; i++) {
            st = new StringTokenizer(br.readLine());
            int a = Integer.parseInt(st.nextToken());
            int b = Integer.parseInt(st.nextToken());
            int c = Integer.parseInt(st.nextToken());
            edges.add(new Node(a, b, c));
        }

        // 벨만-ν¬λ“œ μˆ˜ν–‰
        if (bellmanFord()) {
            System.out.println("-1"); // 음수 사이클 쑴재 μ‹œ -1 좜λ ₯
        } else {
            StringBuilder sb = new StringBuilder();
            for (int i = 2; i <= N; i++) { // 1번 λ„μ‹œ μ œμ™Έ 좜λ ₯
                if (dist[i] == INF) {
                    sb.append("-1\n"); // 도달할 수 μ—†λŠ” 경우 -1 좜λ ₯
                } else {
                    sb.append(dist[i]).append("\n");
                }
            }
            System.out.println(sb);
        }
    }

    private static boolean bellmanFord() {
        boolean hasCycle = false;

        // N-1번 반볡 (μ΅œλ‹¨ 거리 κ°±μ‹ )
        for (int i = 1; i < N; i++) {
            for (Node edge : edges) {
                if (dist[edge.start] != INF && dist[edge.end] > dist[edge.start] + edge.time) {
                    dist[edge.end] = dist[edge.start] + edge.time;
                }
            }
        }

        // 음수 사이클 체크 (N번째 κ°±μ‹  μ‹œ 값이 λ³€ν•˜λ©΄ 사이클 쑴재)
        for (Node edge : edges) {
            if (dist[edge.start] != INF && dist[edge.end] > dist[edge.start] + edge.time) {
                hasCycle = true;
                break;
            }
        }

        return hasCycle;
    }
}

 

 



πŸ” μ½”λ“œ μ„€λͺ…

 

πŸ“Œ 1. κ·Έλž˜ν”„ μž…λ ₯ 및 μ΄ˆκΈ°ν™”

edges = new ArrayList<>();
dist = new long[N + 1];
Arrays.fill(dist, INF);
dist[1] = 0; // μ‹œμž‘μ  거리 0

βœ” μ΅œλ‹¨ 거리 λ°°μ—΄(dist[])을 INF둜 μ΄ˆκΈ°ν™”

βœ” 1번 λ„μ‹œμ—μ„œ μΆœλ°œν•˜λ―€λ‘œ dist[1] = 0 μ„€μ •

 



πŸ“Œ 2. 벨만-ν¬λ“œ μ•Œκ³ λ¦¬μ¦˜ μˆ˜ν–‰

for (int i = 1; i < N; i++) { // N-1번 반볡
    for (Node edge : edges) {
        if (dist[edge.start] != INF && dist[edge.end] > dist[edge.start] + edge.time) {
            dist[edge.end] = dist[edge.start] + edge.time;
        }
    }
}

βœ” λͺ¨λ“  간선을 ν™•μΈν•˜λ©° N-1번 λ™μ•ˆ μ΅œλ‹¨ 거리 κ°±μ‹ 

βœ” ν˜„μž¬ 간선을 톡해 더 짧은 거리가 μ‘΄μž¬ν•˜λ©΄ κ°±μ‹ 

 



πŸ“Œ 3. 음수 사이클 쑴재 μ—¬λΆ€ 검사

for (Node edge : edges) {
    if (dist[edge.start] != INF && dist[edge.end] > dist[edge.start] + edge.time) {
        hasCycle = true;
        break;
    }
}

βœ” N번째 λ°˜λ³΅μ—μ„œ 값이 λ³€κ²½λ˜λ©΄ 음수 사이클이 μ‘΄μž¬ν•¨

βœ” 즉, μ΅œλ‹¨ 경둜λ₯Ό 계속 κ°±μ‹ ν•  수 μžˆλŠ” 경우λ₯Ό 찾음

 



πŸ“Œ 4. μ΅œλ‹¨ 거리 좜λ ₯

StringBuilder sb = new StringBuilder();
for (int i = 2; i <= N; i++) {
    if (dist[i] == INF) {
        sb.append("-1\n"); // 도달할 수 μ—†λŠ” 경우
    } else {
        sb.append(dist[i]).append("\n");
    }
}
System.out.println(sb);

βœ” 1번 λ„μ‹œμ—μ„œ 2~N번 λ„μ‹œλ‘œμ˜ μ΅œλ‹¨ 거리 좜λ ₯

βœ” 도달할 수 μ—†λŠ” 경우 -1 좜λ ₯

 



πŸ† 정리

 

βœ… 핡심 포인트

 

βœ” 벨만-ν¬λ“œ μ•Œκ³ λ¦¬μ¦˜μ„ μ‚¬μš©ν•˜μ—¬ μ΅œλ‹¨ 경둜 계산

βœ” 음수 κ°€μ€‘μΉ˜κ°€ μ‘΄μž¬ν•  수 μžˆμœΌλ―€λ‘œ λ‹€μ΅μŠ€νŠΈλΌκ°€ μ•„λ‹Œ 벨만-ν¬λ“œ ν™œμš©

βœ” N번째 λ°˜λ³΅μ—μ„œλ„ 값이 κ°±μ‹ λ˜λ©΄ 음수 사이클 쑴재 νŒλ³„ κ°€λŠ₯

 

🎯 이 μ•Œκ³ λ¦¬μ¦˜μ˜ μž₯점

 

βœ… 음수 κ°€μ€‘μΉ˜κ°€ μžˆλŠ” μ΅œλ‹¨ 경둜 문제 ν•΄κ²° κ°€λŠ₯

βœ… 음수 사이클 νŒλ³„μ΄ κ°€λŠ₯ν•˜μ—¬ λ¬΄ν•œ κ°μ†Œν•˜λŠ” 경둜λ₯Ό 감지

βœ… O(NM) λ³΅μž‘λ„λ‘œ ν•΄κ²° κ°€λŠ₯ν•˜μ—¬ 크기가 μž‘μ„ λ•Œ 유용

 


이 글이 도움이 λ˜μ…¨λ‹€λ©΄ μ’‹μ•„μš”μ™€ 곡유 λΆ€νƒλ“œλ¦½λ‹ˆλ‹€! 😊