ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • 11657번 - 타임머신
    알고리즘/백준 2023. 7. 16. 12:51

    1️⃣ Bellman-Ford 알고리즘

     

    ✏️ 풀이 과정

    벨만-포드 알고리즘을 구현하면 끝나는 문제입니다. 주의할 점은 음수 가중치가 있는 부분에서 사이클이 발생할 경우 가중치가 계속 낮아지는 것이 가능하다는 것입니다.(돌았을 때 마진이 -인 사이클이 있으면 사이클 입구 지점이 업데이트되고 또 같은 경로로 업데이트하며 사이클을 돌고...가 무한으로 반복됩니다.) 이를 판별하는 방법은 for문을 N번 실행해서(일직선 연결을 가정한 N-1이 가능한 최대 업데이트 횟수인데 N번 업데이트되었다는 것은 무한 업데이트를 만드는 사이클이 존재함을 의미합니다.)

     

    이 알고리즘의 효율성을 높이는 방법이 있는데 바로 업데이트 여부를 체크함으로써 N-1번의 실행을 다 완료하지 않고도 업데이트가 한 번도 되지 않았을 경우 종료하는 것입니다.(한 번의 반복마다 모든 간선을 체크하는 것이기 때문에 한 번 일어나지 않으면 앞으로도 업데이트가 되지 않습니다.)

     

    구현할 때 dist 배열의 경우 반드시 long으로 선언해야 합니다. 10000 * N = 5000000까지만 늘어날 수 있다고 생각하기 쉬운데 사이클이 존재할 경우 업데이트가 매번 일어나는 것이 가능해져 음수 방향으로 for문 1회마다 -10000 * 6000만큼 줄어들게 됩니다. 따라서 약 -10000 * 500 * 6000 = -30000000000까지 int 범위를 초과해 언더플로우가 일어날 수 있기 때문에 long으로 선언해야만 이를 방지할 수 있습니다.

     

    ⏱ 시간 복잡도

    벨만-포드 알고리즘은 M개의 간선을 N-1번(사이클을 체크하려면 N번) 순회하기 때문에 시간 복잡도는 O(N*M)입니다. N이 500까지, M이 6000까지이므로 3000000을 조금 상회하는 정도의 계산량을 예측할 수 있습니다. 벨만-포드는 모든 간선을 체크하여 비효율적이기 때문에 이를 개선한 SPFA알고리즘을 사용하면 좀 더 빠르게 문제를 해결할 수 있습니다.

     

    💻 코드

    Java

    import java.io.BufferedReader;
    import java.io.IOException;
    import java.io.InputStreamReader;
    import java.util.StringTokenizer;
    
    public class Main{
    	
    	public static void main(String[] args) throws IOException {
    		BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
    		StringTokenizer st = new StringTokenizer(br.readLine());
    		StringBuilder sb = new StringBuilder();
    		int N = Integer.parseInt(st.nextToken());
    		int M = Integer.parseInt(st.nextToken());
    		int[][] Edges = new int[M][3];
    		long[] dist = new long[N+1];
    		int INF = 999999999;
    		for(int i=2;i<=N;i++) {
    			dist[i] = INF;
    		}
    		for(int i=0;i<M;i++) {
    			st = new StringTokenizer(br.readLine());
    			Edges[i][0] = Integer.parseInt(st.nextToken());
    			Edges[i][1] = Integer.parseInt(st.nextToken());
    			Edges[i][2] = Integer.parseInt(st.nextToken());
    		}
    		boolean update;
    		for(int i=0;i<N;i++) {
    			update = false;
    			for(int j=0;j<M;j++) {
    				if(dist[Edges[j][0]] != INF && dist[Edges[j][0]] + Edges[j][2] < dist[Edges[j][1]]) {
    					update = true;
    					dist[Edges[j][1]] = dist[Edges[j][0]] + Edges[j][2];
    					if(i == N-1) {
    						System.out.println(-1);
    						System.exit(0);
    					}
    				}
    			}
    			if(!update) {
    				break;
    			}
    		}
    		for(int i=2;i<=N;i++) {
    			sb.append(dist[i] == INF ? -1 : dist[i]);
    			sb.append("\n");
    		}
    		System.out.print(sb);
    		br.close();
    	}
    }

    '알고리즘 > 백준' 카테고리의 다른 글

    13023번 - ABCDE  (0) 2023.07.18
    1865번 - 웜홀  (0) 2023.07.16
    1939번 - 중량제한  (0) 2023.07.15
    17144번 - 미세먼지 안녕!  (0) 2023.07.15
    17276번 - 배열 돌리기  (0) 2023.07.13
Designed by Tistory.