Algorithm

[μ•Œκ³ λ¦¬μ¦˜] Floyd-Warshall ν”Œλ‘œμ΄λ“œ-와샬 μ•Œμ•„λ³΄κΈ° ( λ°±μ€€ 11404번 경둜 μ°ΎκΈ° with μžλ°” )

μž₯μš©μ„ 2024. 2. 29. 18:26

 

πŸ€” Floyd-Warshall ν”Œλ‘œμ΄λ“œ-와샬 μ•Œκ³ λ¦¬μ¦˜?

κ·Έλž˜ν”„μ— μžˆλŠ” λͺ¨λ“  정점에 λŒ€ν•΄ 각 정점듀이 λ‹€λ₯Έ μ •μ λ“€κΉŒμ§€ λ„λ‹¬ν•˜κΈ° μœ„ν•΄ ν•„μš”ν•œ λͺ¨λ“  μ΅œλ‹¨ 거리λ₯Ό κ΅¬ν• λ•Œ μ‚¬μš©ν•©λ‹ˆλ‹€.

ν”Œλ‘œμ΄λ“œ-와샬 μ•Œκ³ λ¦¬μ¦˜μ€ κ±°μ³κ°€λŠ” 정점을 κΈ°μ€€μœΌλ‘œ μ•Œκ³ λ¦¬μ¦˜μ„ μˆ˜ν–‰ν•˜λŠ” νŠΉμ§•μ΄ μžˆμŠ΅λ‹ˆλ‹€.

 

즉, 정점 A, 정점B κΉŒμ§€μ˜ μ΅œλ‹¨ 거리λ₯Ό κ΅¬ν•˜κΈ° μœ„ν•΄ μ€‘κ°„μ—μ„œ 거쳐갈 수 μžˆλŠ” λͺ¨λ“  정점듀을 확인해보고 κ·Έ 쀑 μ΅œλ‹¨ 거리의 경둜λ₯Ό μ°ΎμŠ΅λ‹ˆλ‹€.

 

(ν”Œλ‘œμ΄λ“œ 와샬은 λ‹€μ΄λ‚˜λ―Ή ν”„λ‘œκ·Έλž˜λ° 기법을 μ‚¬μš©ν•œ μ•Œκ³ λ¦¬μ¦˜μ΄κ³ , 인접 ν–‰λ ¬λ‘œ ν‘œν˜„ν•˜μ—¬ μ΅œλ‹¨ 거리λ₯Ό κ³„μ‚°ν•©λ‹ˆλ‹€.)

 

 

βœ” μ‹œκ°„λ³΅μž‘λ„

3쀑 for문을 톡해 κ±°μ³κ°€λŠ” 정점을 μ΄μš©ν•˜μ—¬ κ·Έλž˜ν”„λ₯Ό νƒμƒ‰ν•˜κΈ° λ•Œλ¬Έμ— O(n^3)의 μ‹œκ°„λ³΅μž‘λ„λ₯Ό κ°–μŠ΅λ‹ˆλ‹€.

 

 

βœ” 탐색 방법

λ¬Έμ œμ™€ ν•¨κ»˜ ν”Œλ‘œμ΄λ“œ-와샬 μ•Œκ³ λ¦¬μ¦˜μ˜ 탐색방법을 μ‚΄νŽ΄λ³΄κ² μŠ΅λ‹ˆλ‹€.

 

λ°±μ€€ 11404번 ν”Œλ‘œμ΄λ“œ 

λ‚œμ΄λ„ : κ³¨λ“œ πŸ₯‡

 

11404번: ν”Œλ‘œμ΄λ“œ

첫째 쀄에 λ„μ‹œμ˜ 개수 n이 μ£Όμ–΄μ§€κ³  λ‘˜μ§Έ μ€„μ—λŠ” λ²„μŠ€μ˜ 개수 m이 μ£Όμ–΄μ§„λ‹€. 그리고 μ…‹μ§Έ 쀄뢀터 m+2μ€„κΉŒμ§€ λ‹€μŒκ³Ό 같은 λ²„μŠ€μ˜ 정보가 μ£Όμ–΄μ§„λ‹€. λ¨Όμ € μ²˜μŒμ—λŠ” κ·Έ λ²„μŠ€μ˜ 좜발 λ„μ‹œμ˜ λ²ˆν˜Έκ°€

www.acmicpc.net

 

 

μœ„ 예제λ₯Ό κ·Έλž˜ν”„λ‘œ ν‘œν˜„ν•˜λ©΄ μ˜†μ˜ 그림처럼 ν‘œν•œν•  수 μžˆμŠ΅λ‹ˆλ‹€.

각 정점듀은 λ„μ‹œμ΄κ³  ν™”μ‚΄ν‘œμ˜ μˆ«μžλŠ” λ„μ‹œμ—μ„œ λ‹€λ₯Έ λ„μ‹œλ‘œ κ°€κΈ°μœ„ν•œ λΉ„μš©μž…λ‹ˆλ‹€.

λ¬Έμ œλŠ” λͺ¨λ“  λ„μ‹œμ˜ μŒμ— λŒ€ν•΄μ„œ λ„μ‹œAμ—μ„œ B둜 κ°€λŠ”λ° ν•„μš”ν•œ μ΅œμ†Œ λΉ„μš©μ„ ꡬ해야 ν•©λ‹ˆλ‹€.

ν”Œλ‘œμ΄λ“œ-와샬 μ•Œκ³ λ¦¬μ¦˜μ€  λͺ¨λ“  μ •점에 λŒ€ν•΄ κ° 정점듀이 λ‹€λ₯Έ μ •μ λ“€κΉŒμ§€ λ„λ‹¬ν•˜κΈ° μœ„ν•΄ ν•„μš”ν•œ λͺ¨λ“  μ΅œλ‹¨ 거리λ₯Ό κ΅¬ν• λ•Œ μ‚¬μš©ν•©λ‹ˆλ‹€.

즉, 이 문제 풀이에 μ μš©ν•΄λ³Ό 수 μžˆκ² μŠ΅λ‹ˆλ‹€.

 

 

각 μ •μ μ—μ„œ λ‹€λ₯Έ μ •μ κΉŒμ§€μ˜ μ΅œμ†Œ λΉ„μš©μ„ 이차원 λ°°μ—΄μ˜ ν˜•νƒœλ‘œ ν‘œν˜„ν•˜λ©΄ μ•„λž˜μ™€ 같이 ν‘œν˜„ν•  수 μžˆμŠ΅λ‹ˆλ‹€.

( 0은 자기 μžμ‹ (A, A)이기 λ•Œλ¬Έμ— λΉ„μš©μ΄ 0원 μž…λ‹ˆλ‹€, X λŠ” μ—°κ²°λ˜μ§€ μ•Šμ•„ 갈 수 μ—†λŠ” λΆ€λΆ„μž…λ‹ˆλ‹€ )

0 2 3 1 10
X 0 X 2 X
8 X 0 1 1
X X X 0 3
7 4 X X 0
		int n = Integer.parseInt(br.readLine()); // 5 λ„μ‹œμ˜ 수
        int m = Integer.parseInt(br.readLine()); // 14 λ„μ‹œμ™€ μ—°κ²°λœ 경둜의 수
        int x = 100000 * (n-1) + 1;
        int[][] city = new int[n + 1][n + 1];
        
        // 초기 이차원 λ°°μ—΄ 전체λ₯Ό x와 0원인 뢀뢄은 0이 λ˜λ„λ‘ μ„ΈνŒ…ν•΄μ€λ‹ˆλ‹€.
        for (int i = 1; i < city.length; i++) {
            for( int j = 1; j<city[i].length; j++){
                city[i][j] = x;
                if( i == j ){
                    city[i][j] = 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 cost = Integer.parseInt(st.nextToken());

            city[a][b] = Math.min(city[a][b], cost);
        }

 

πŸ“Œ  μ—°κ²°λ˜μ§€ μ•Šμ€ X의 κ°’ μ„€μ •

μ΅œλŒ€κ°’(λ¬΄ν•œ)을 μƒκ°ν•΄μ„œ Integer.MAX_VALUEλ₯Ό μ„€μ •ν•΄ λ³΄μ•˜μ§€λ§Œ λ‹€λ₯Έ 경둜의 λΉ„μš©κ³Ό ν•©μ³μ§€κ²Œ 되면 μŒμˆ˜κ°€ λ˜μ–΄ 였λ₯˜κ°€ λ°œμƒν•©λ‹ˆλ‹€ 😭

 

int x = 100000 * ( n - 1 ) + 1
λΉ„μš©(μ—°κ²°λœ κ°„μ„ μ˜ κ°€μ€‘μΉ˜) μ˜ μ΅œλŒ€κ°’ * κ°„μ„ μ˜ μˆ˜(=λ…Έλ“œμ˜ μˆ˜  - 1 ) λ³΄λ‹€ μ»€μ•Όν•˜κΈ° λ•Œλ¬Έμ— + 1

 

κ²½λ‘œκ°€ μ—†λŠ” 뢀뢄을 μ΅œλŒ€κ°’(λ¬΄ν•œ)으둜 μ„€μ •ν•˜λŠ” μ΄μœ λŠ” μ‹€μ œ κ²½λ‘œκ°€ μ‘΄μž¬ν•˜μ§€ μ•ŠμŒμ„ λ‚˜νƒ€λ‚΄κΈ° μœ„ν•¨μž…λ‹ˆλ‹€.
예λ₯Όλ“€μ–΄ 1->2->3->4->5 처럼 λͺ¨λ“  경둜λ₯Ό κ±°μ³μ„œ λ„μ°©ν•œ λΉ„μš©μ€
λΉ„μš© * κ°„μ„ μ˜ μˆ˜ λ‘œ ν‘œν˜„ν•  μˆ˜ μžˆμŠ΅λ‹ˆλ‹€ ν•˜μ§€λ§Œ λ§Œμ•½ κ²½λ‘œκ°€ μ—†λŠ” xκ°€ λͺ¨λ“  κ²½λ‘œλ₯Ό κ±°μΉœ λΉ„μš©λ³΄λ‹€ μž‘λ‹€λ©΄ ν”Œλ‘œμ΄λ“œ-와샬 μ•Œκ³ λ¦¬μ¦˜μ€ κ²½λ‘œκ°€ μ—†λŠ” x의 κ°’μœΌλ‘œ λΉ„μš©μ„ μ„ΈνŒ…ν•˜κ²Œλ˜μ–΄ μ•Œκ³ λ¦¬μ¦˜μ˜ μ˜€λ₯˜λ‘œ μ΄μ–΄μ§€κ²Œ λ©λ‹ˆλ‹€.

 

 

μ„ΈνŒ…λœ 이차원 배열에 ν”„λ‘œμ΄λ“œ-와샬 μ•Œκ³ λ¦¬μ¦˜μ„ μ‚¬μš©ν•˜μ—¬ μ΅œμ†Œ λΉ„μš©μ„ νƒμƒ‰ν•©λ‹ˆλ‹€.

for( int k = 1; k<=n; k++){          // k : κ±°μ³κ°€λŠ” λ„μ‹œ
    for( int i = 1; i<=n; i++){      // i : λ„μ‹œA
        for( int j = 1; j<=n; j++){  // j : λ„μ‹œB
            if( i != j){
                city[i][j] = Math.min(city[i][j], city[i][k] + city[k][j]);
            }
        }
    }
}

 

κ²½λ‘œκ°€ μžˆμ„ 경우 ( 예 : k = 1, i = 3, j = 4 )

city[3][4] 3(i)μ—μ„œ 4(j)λ₯Ό λ°”λ‘œ κ°€λŠ” 경우 vs city[i][k] + city[k][j]  3(i)μ—μ„œ1(k)을 거쳐 4(j)둜 κ°€λŠ” 경우λ₯Ό λΉ„κ΅ν•˜μ—¬  더 적은 λΉ„μš©μ„ μ„ΈνŒ…ν•©λ‹ˆλ‹€. ( 1둜 μ„ΈνŒ… )

 

κ²½λ‘œκ°€ 없을 경우 ( 예 : k = 2, i = 4, j = 5 )

city[i][j] = 3 vs city[i][k] + city[k][j] = X + X

κ²½λ‘œκ°€ μ—†μ„κ²½μš° Xλ₯Ό λ”ν•˜κ²Œ 됨으둜 λ°”λ‘œ κ°€λŠ” κ²½λ‘œκ°€ μžˆλ‹€λ©΄ λ‹Ήμ—°νžˆ κ±°μ³κ°€λŠ” κ²½λ‘œλ³΄λ‹€ μž‘κΈ° λ•Œλ¬Έμ— λ°”λ‘œ κ°€λŠ” κ²½λ‘œκ°€ μ„ΈνŒ…λ˜μ–΄μ§‘λ‹ˆλ‹€ ( 3으둜 μ„ΈνŒ… )

 

이처럼 λ°”λ‘œ κ°€λŠ” κ²½λ‘œμ™€, κ±°μ³κ°€λŠ” 경둜λ₯Ό λͺ¨λ‘ λΉ„κ΅ν•˜λ©΄μ„œ 각 μ •μ κ³Όμ˜ μ΅œμ†Œ λΉ„μš©(λ˜λŠ” μ΅œλ‹¨ 거리)λ₯Ό 이차원 λ°°μ—΄λ‘œ λ‚˜νƒ€λ‚Ό 수 μžˆκ²Œλ©λ‹ˆλ‹€.

 

 

πŸ”Ž 전체 μ½”λ“œ

import java.io.IOException;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.util.StringTokenizer;
import java.lang.StringBuilder;

public class Main{
	public static void main(String[] args) throws IOException {
       	BufferedReader br = new BufferedReader( new InputStreamReader(System.in));
	    StringBuilder sb = new StringBuilder();
        StringTokenizer st;
        
        int n = Integer.parseInt(br.readLine());
        int m = Integer.parseInt(br.readLine());
        int x = 100000 * (n-1) + 1;
        int[][] city = new int[n + 1][n + 1];
        for (int i = 1; i < city.length; i++) {
            for( int j = 1; j<city[i].length; j++){
                city[i][j] = x;
                if( i == j){
                    city[i][j] = 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 cost = Integer.parseInt(st.nextToken());

            city[a][b] = Math.min(city[a][b], cost);
        }


        for( int k = 1; k<=n; k++){
            for( int i = 1; i<=n; i++){
                for( int j = 1; j<=n; j++){
                    if( i != j){
                        city[i][j] = Math.min(city[i][j], city[i][k] + city[k][j]);
                    }
                }
            }
        }

        for( int i = 1; i<=n; i++){
            for (int j = 1; j <= n; j++) {
                if (city[i][j] == x) {
                    city[i][j] = 0;
                }
                sb.append(city[i][j]).append(" ");
            }
            sb.append("\n");
        }

        System.out.println(sb);
        

        br.close();
	}
}