3학년 1학기/알고리즘 (Algorithm)

[ 알고리즘 ] 19. Floyd Algorithm

쫑알bot 2024. 5. 21. 12:41
728x90

Floyd Algorithm

: All Pairs Shortest Path 를 구하기 위한 알고리즘이다.

 From all to all

 

 

 

Dense graph는, Edge의 개수 = O(V^2)인 경우의 graph이다.

E에 V^2를 대입하면 과 같다

 

 

● Floyd Algorithm 사용 조건

 - Negative Edge 는 가능

 - 하지만 Negative Weight cycle은 안 된다.

 - DP로 구현한다. = Optimal Substructure 적용 가능

 

 

 

알아야 하는 개념

- Intermediate Vertex

  : i에서 k까지 가는 path에 포함되는 Vertex

    단, 한 번만 나올 수 있다.

 

DP로 생각해보면 1 ~ ... k-1까지 가는 최단 경로를 찾았다면

 k까지 갈 땐 k-1까지의 최단 경로를 사용하여 길을 찾을 수 있다.

 

shortest path에서는 같은 vertex가 2번 선택되지 않는다.

 

 

 


대략적인 푸는 개념

i에서 j까지 가는 최단 거리를 p라고 가정한다.

vertex들은 {1,...k-1}까지 가 intermediate가 될수 있다.

 

- Case 1 : k가 p의 intermediate가 아닐 때

  = Shortest path 의 intermediate 는 { 1 ~ k-1 }이다. 

 

 

- Case 2 : k가 p의 intermediate일 때

    = Path p는 p1 = [ i ~ k ] / p2= [  k~ j ]로 나눌 수 있다.

 

    p1 즉, i~k 사이에 올 수 있는 intermediate vertex는 {1~k-1}

    p2 k~j 사이에도 올 수 있는 intermediate vertex는 {1~k-1}

 

 


 

d ij (k)

= i~j까지 가는 최단 경로에 Intermediate vertex는 {1~k}가 될 수 있다.

 

 

D(k)

= n*n matrix를 만든 것 [ d ij (k) ] ▼

 

 

- 세로 = 출발하는 node

- 가로 = 도착하는 node

 

- D(a) = intermediate vertex로 a를 추가(고려).

  ex ) D(0) = 1에서 0을 거쳐서 가는 Distance

 

 - ㅠ는 현재 새롭게 추가된 intermediate 로 인해서
   경로가 새로 업데이트되는 경우에 해당 intermediate vertex를 업데이트 한다.

 

= D를 통해 Distance를 구하고

  ㅠ 를 통해서 Path를 구한다.

 

 

d ij(0) 이면 그냥 각자의 weight으로 matrix를 채우면 된다

 

 

k가 Intermediate가 아닌 경우 vs 맞는 경우 중에서 작은 걸 골라 d ij (k)로 설정한다.

 

 

▼ 예

더보기

1번에서 3번으로 가는 edge = 8

2번에서 1번으로 가는 edge = 무한대

2번에서 3번 가는 edge = 무한대

4번에서 5번 가는 edge = 무한대

 

 

만약에 1번 vertex를 intermediate로 추가하면

4 1 5가 가능하기 때문에 2 +(-4) 를 해서 -2를 추가할 수 있고,

ㅠ에는 1을 통해 minmum이 되었기에 1을 추가한다.

 

 

 

 


그럼 Shotest path의 Distance를 구하고, 그 경로를 어떻게 찾냐?

- 자기 자신으로 가는 것이나, 경로가 없는 것 = 무한대

- 자기 자신이 아니고, 경로가 존재하면 = i 

- 또한 Shortest path에서 새로운 intermediate vertex k로 인해 더 짧은 경로를 찾았다면

   prde[i,j] = k로 업데이트 한다.

 

  ▼ 아래를 보고 이해할 수 있다.

 

 

- 만약 모든 node에 대해 다 돌렸는데도 Pred[ i,j ] = nil 라면 , path가 존재하지 않는다는 의미이다.

- path가 존재하는데, intermediate 로 인해 업데이트 된 적 없다면 shortest path는 direct edge이다.

 

 

 

- pred[i,j] = i 라면 , shortest path 는 (i,j) edge이다.

- pred[i,j] = i 가 아니라면 , recursive compute로 ( i,pred[ i,j ] ) and ( pred[ i,j ] , j )

 

 

 


 

알고리즘 Ver.1

 

 

 

우선 윗부분은 초기화 단계이다.

for 안에 내용은 Intermediate vertex가 없을 때

Distance는 Edge weight으로 설정한다.

 

 

intermediate K 를 거치는 것과 그렇지 않은 것 중에 뭐가 더 작은지 판단.

▶ 거치는 것이 빠르면 distance 를 업데이트하고

▶ Pred 를 k로 업데이트한다.

 

 

다음 Matrix에서 1에서 2로 가는 최단 경로를 구해보자.

1`~ 2의 Intermediate vertex는 3이다.

  =13 , 32로 가야한다.    [ 13, 32 ]

    ● 1~3 으로 가는 경로를 보자.

     > 4가 Intermediate vertex이다.

     = 14~ 43 이 되어야 함. [14 ,43, 32 ]

                ● 1~4 로 가는 경로를 보자 

                 > 5가 Intermediate vertex이다.

                  15 54가 되어야 함  [ 15, 54, 43, 32 ]

 

 

Running Time : 세타(n^3)   (n=Vertex로 해도 됨)

 

근데 이거 세타(V^2)으로 줄일 수도 있음

 

하나의 Intermediate Vertex가 생길 때마다 Matrix 하나씩 더 추가하는 게 아니라

n번째 단계를 만들기 위해 필요한 n-1번째 matrix 가 아니면 그 위에 덮는 것이다.

a matrix , b matrix있으면

1번 = a에 씀

2번 = b에 씀

3번을 만들 때는 b의 정보만 필요하므로 a위에 덮어 씀

4번을 만들 때는 3번의 정보 = a 의 정보만 필요하므로 b에 덮어 쓴다.

...반복

 

메모리에 관련된 문제를 해결할 수 있다.

 

 

 


왼쪽이 새로 만들어진 코드임.

if 에 (k-1)가 사라진다.

굳이 그걸 고려할 필요가 없이 돌면 되는 거라 그런 것 같다.

 

 


Transitive Closure

: Path가 존재하는지 알아내기

 

● 푸는 방법

: 모든 Edge의 weight를 1로 설정해두고 Floyd 알고리즘을 적용한다.

 

그 결과 , d<0보다 크다면 path가 존재한다는 뜻이고

               d=무한대 라면 path가 존재하지 않는다는 뜻이다.

 

 

  


추가로 OR과 AND로도 풀 수 있다.

Edge의 weight 을 그대로 1로 매긴 뒤에

 

- 길이 없으면 0

- 길이 있으면 1로 초기화 시킨 뒤

 

i~j에 k가 intermediate인 vertex라고 했을 때

- 길이 k를 포함시키는 것이든, 아니든 존재하면 1

- 그렇지 않으면 0

 

 

 

 

풀어보자

자기 자신은 다 1로 해둔다.

1빼고는 결국에는 서로 어디든 갈 수 있다.

 

 

 

(출처)

한동대학교 용환기교수님 - 알고리즘