수색…


비고

유향 그래프 G 가 주어지면 주어진 노드 A 에서 그래프의 나머지 노드까지의 최단 거리를 찾고 싶습니다. Dijkstra 알고리즘은 최단 경로를 찾는 가장 유명한 알고리즘이지만 주어진 그래프의 에지 가중치가 음수가 아닌 경우에만 작동합니다. Bellman-Ford 는 가중치의 일부가 음수 일지라도 지정된 노드 (존재하는 경우)에서 최단 경로를 찾는 것을 목표로합니다. 그래프에 음의주기가있는 경우 최단 거리가 존재하지 않을 수 있습니다 (이 경우 순환을 따라 가면서 총 거리가 무한히 짧아 질 수 있음). Bellman-Ford는 또한 우리가 그러한주기의 존재를 결정할 수있게 해줍니다.

알고리즘의 총 복잡도는 O(V*E) . 여기서 V -는 꼭짓점 수 및 E 가장자리 수입니다

단일 소스 최단 경로 알고리즘 (그래프에 음의 사이클이 있음)

이 예를 읽기 전에 가장자리 완화에 대한 간단한 아이디어가 필요합니다. 여기 에서 배울 수 있습니다.

Bellman-Ford Algorithm은 단일 소스 버텍스에서 가중치가있는 다이 그래프의 다른 모든 버텍스까지의 최단 경로를 계산합니다. Dijkstra 's Algorithm 보다 느리지 만 가장자리의 무게가 음수이고 그래프에서 음의 가중치 사이클을 발견하는 경우에도 작동합니다. Dijkstra 's 알고리즘의 문제는 부정적인 사이클이 반복되면 사이클을 계속 반복하면서 두 개의 정점 사이의 거리를 줄이는 것입니다.

이 알고리즘의 아이디어는 임의의 순서로이 그래프의 모든 가장자리를 하나씩 살펴 보는 것입니다. 무작위 순서 일 수 있습니다. 그러나 uv ( uv 가 그래프의 두 정점 인 경우)가 주문 중 하나 인 경우 u 에서 v 까지의 모서리가 있어야합니다. 대개 주어진 입력의 순서에서 직접 가져옵니다. 다시 말하지만 임의의 임의 순서로 작동합니다.

순서를 선택하면, 우리는 이완 식에 따라 에지 이완된다. u 에서 v로 진행하는 주어진 에지 uv에 대해 이완 수식은 다음과 같습니다.

if distance[u] + cost[u][v] < d[v]
    d[v] = d[u] + cost[u][v]

즉, 소스 에서 임의의 정점 u + 에지 uv 의 무게까지의 거리가 소스 에서 다른 정점 v 까지의 거리보다 작은 경우 소스 에서 v 까지의 거리를 업데이트합니다. 우리는 최대 (V-1) 배의 가장자리를 완화 해야합니다. 여기서 V 는 그래프의 가장자리 수입니다. 왜 (V-1) 물어 보시겠습니까? 다른 예를 들어 설명하겠습니다. 또한 우리는 어떤 꼭지점의 부모 꼭지점을 추적 할 것입니다. 즉, 가장자리를 풀 때 우리는 다음을 설정합니다 :

parent[v] = u

그것은 우리가 u 를 통해 v 에 도달하는 또 다른 짧은 길을 발견했다는 것을 의미합니다. 소스 에서 정점으로가는 최단 경로를 인쇄하려면 나중에이 작업이 필요합니다.

예를 살펴 보겠습니다. 그래프가 있습니다. 예제 그래프

소스 정점으로 1 을 선택했습니다. 소스 에서 다른 모든 정점까지의 최단 경로를 찾고 싶습니다.

처음에 d [1] = 0 이기 때문에 소스입니다. 그리고 우리는 아직 거리를 알지 못하기 때문에 휴식은 무한 합니다.

이 시퀀스에서 가장자리를 완화합니다.

+--------+--------+--------+--------+--------+--------+--------+
| Serial |    1   |    2   |    3   |    4   |    5   |    6   |
+--------+--------+--------+--------+--------+--------+--------+
|  Edge  |  4->5  |  3->4  |  1->3  |  1->4  |  4->6  |  2->3  |
+--------+--------+--------+--------+--------+--------+--------+

원하는 모든 순서를 취할 수 있습니다. 우리가 한 번 가장자리를 휴식을 취하면, 우리는 무엇을합니까? 소스 에서 최대 1 개의 가장자리를 사용하는 경로의 다른 모든 정점까지의 거리를 구합니다. 이제 가장자리를 풀고 d [] 값을 업데이트합시다. 우리는 얻는다 :

  1. d [4] + 비용 [4] [5] = 무한대 + 7 = 무한대 . 우리는 이것을 업데이트 할 수 없습니다.
  2. d [2] + 비용 [3] [4] = 무한대 . 우리는 이것을 업데이트 할 수 없습니다.
  3. d [1] + 비용 [1] [2] = 0 + 2 = 2 < d [2] . 그래서 d [2] = 2 입니다. 또한 parent [2] = 1 입니다.
  4. d [1] + 비용 [1] [4] = 4 . 그래서 d [4] = 4 < d [4] . parent [4] = 1 .
  5. d [4] + 비용 [4] [6] = 9 . d [6] = 9 < d [6] . parent [6] = 4 .
  6. d [2] + 비용 [2] [2] = 무한대 . 우리는 이것을 업데이트 할 수 없습니다.

d[u] + cost[u][v] < d[v] 조건이 일치하지 않아 일부 정점을 업데이트 할 수 없습니다. 이전에 말했듯이 소스 에서 다른 노드까지의 경로는 최대 1 에지를 사용합니다. 첫 번째 반복 이후

두 번째 반복은 2 개의 노드를 사용하여 경로를 제공합니다. 우리는 얻는다 :

  1. d [4] + 비용 [4] [5] = 12 < d [5] . d [5] = 12 이다. parent [5] = 4 .
  2. d [3] + 비용 [3] [4] = 1 < d [4] . d [4] = 1 이다. parent [4] = 3 .
  3. d [3] 은 변하지 않는다.
  4. d [4] 는 변하지 않는다.
  5. d [4] + 비용 [4] [6] = 6 < d [6] . d [6] = 6 이다. parent [6] = 4 .
  6. d [3] 은 변하지 않는다.

우리의 그래프는 다음과 같습니다 : 두 번째 반복 이후

3 번째 반복은 d [5]8 일 때만 꼭지점 5를 업데이트합니다. 우리의 그래프는 다음과 같습니다 : 세 번째 반복 이후

얼마나 많은 반복이 있더라도 우리는 같은 거리를 가질 것입니다. 업데이트가 발생하는지 여부를 확인하는 플래그를 유지합니다. 그렇지 않다면 루프를 해제 할 것입니다. 우리의 의사 코드는 다음과 같습니다.

Procedure Bellman-Ford(Graph, source):
n := number of vertices in Graph
for i from 1 to n
    d[i] := infinity
    parent[i] := NULL
end for
d[source] := 0
for i from 1 to n-1
    flag := false
    for all edges from (u,v) in Graph
        if d[u] + cost[u][v] < d[v]
            d[v] := d[u] + cost[u][v]
            parent[v] := u
            flag := true
        end if
    end for
    if flag == false
        break
end for
Return d

부정 사이클을 추적하기 위해 여기에 설명 된 절차를 사용하여 코드를 수정할 수 있습니다 . 완료된 의사 코드는 다음과 같습니다.

Procedure Bellman-Ford-With-Negative-Cycle-Detection(Graph, source):
n := number of vertices in Graph
for i from 1 to n
    d[i] := infinity
    parent[i] := NULL
end for
d[source] := 0
for i from 1 to n-1
    flag := false
    for all edges from (u,v) in Graph
        if d[u] + cost[u][v] < d[v]
            d[v] := d[u] + cost[u][v]
            parent[v] := u
            flag := true
        end if
    end for
    if flag == false
        break
end for
for all edges from (u,v) in Graph
    if d[u] + cost[u][v] < d[v]
        Return "Negative Cycle Detected"
    end if
end for
Return d

인쇄 경로 :

정점에 대한 최단 경로를 인쇄하려면 NULL 을 찾아서 정점을 인쇄 할 때까지 부모로 다시 반복합니다. 의사 코드는 다음과 같습니다.

Procedure PathPrinting(u)
v := parent[u]
if v == NULL
    return
PathPrinting(v)
print -> u

복잡성:

에지 최대 값 (V-1) 을 완화해야하므로이 알고리즘의 시간 복잡도는 O (V * E) 와 같을 것입니다. 여기서 adjacency list 를 사용하여 그래프를 나타내는 경우 E 는 에지 수를 나타냅니다. 그러나 adjacency matrix 을 사용하여 그래프를 나타낼 경우 시간 복잡도는 O (V ^ 3)가 됩니다. 이유는 adjacency list 을 사용할 때 O (E) 시간에 모든 가장자리를 반복 할 수 있지만 adjacency matrix 을 사용할 때 O (V ^ 2) 시간이 걸립니다.

왜 우리는 대부분 (V-1) 번에 모든 가장자리를 이완시켜야합니까?

이 예제를 이해하려면 여기 에서 찾을 수있는 Bellman-Ford 단일 소스 최단 경로 알고리즘에 대한 간단한 아이디어를 얻는 것이 좋습니다 .

Bellman-Ford 알고리즘에서 최단 경로를 찾으려면 그래프의 모든 가장자리를 완화 해야합니다. 이 프로세스는 최대 (V-1) 번 반복됩니다. 여기서 V 는 그래프의 정점 수입니다.

소스 에서 다른 모든 정점까지의 최단 경로를 찾는 데 필요한 반복 횟수는 가장자리를 완화 하기 위해 선택한 순서에 따라 다릅니다.

예제를 살펴 보겠습니다.

예제 그래프

여기에서 소스 정점은 1입니다. 소스 와 다른 모든 정점 사이의 최단 거리를 찾습니다. 꼭지점 4 에 도달하기 위해, 최악의 경우, (V-1) 개의 가장자리를 취할 것입니다. 이제 가장자리가 발견 된 순서에 따라 정점 4 를 발견하는 데 (V-1) 번 걸릴 수 있습니다. 알았어? Bellman-Ford 알고리즘을 사용하여 여기에서 최단 경로를 찾으십시오.

우리는이 시퀀스를 사용할 것입니다 :

+--------+--------+--------+--------+
| Serial |    1   |    2   |    3   |
+--------+--------+--------+--------+
|  Edge  |  3->4  |  2->3  |  1->2  |
+--------+--------+--------+--------+

첫 번째 반복 :

  1. d [3] + 비용 [3] [4] = 무한대 . 아무것도 바뀌지 않을거야.
  2. d [2] + 비용 [2] [3] = 무한대 . 아무것도 바뀌지 않을거야.
  3. d [1] + 비용 [1] [2] = 2 < d [2] . d [2] = 2 이다. parent [2] = 1 .

우리의 이완 과정은 단지 d [2] 만 바뀌 었음을 알 수 있습니다. 우리의 그래프는 다음과 같습니다 : 첫 번째 반복 이후

두 번째 반복 :

  1. d [3] + 비용 [3] [4] = 무한대 . 아무것도 바뀌지 않을거야.
  2. d [2] + 비용 [2] [3] = 5 < d [3] . d [3] = 5 이다. parent [3] = 2.
  3. 그것은 변경되지 않습니다.

이번에 이완 과정은 d [3]으로 바뀌었다. 우리의 그래프는 다음과 같습니다 : 두 번째 반복 이후

세 번째 반복 :

  1. d [3] + 비용 [3] [4] = 7 < d [4] . d [4] = 7 이다. parent [4] = 3 .
  2. 그것은 변경되지 않습니다.
  3. 그것은 변경되지 않습니다.

3 번째 반복은 마침내 1 에서 4 로 최단 경로를 찾았습니다. 우리의 그래프는 다음과 같습니다 : 세 번째 반복 이후

따라서 최단 경로를 찾는 데는 3 번의 반복이 필요했습니다. 이 후, 몇 번이나 가장자리를 풀어도 d [] 의 값은 그대로 유지됩니다. 이제 우리가 다른 시퀀스를 고려한다면 :

+--------+--------+--------+--------+
| Serial |    1   |    2   |    3   |
+--------+--------+--------+--------+
|  Edge  |  1->2  |  2->3  |  3->4  |
+--------+--------+--------+--------+

우리는 얻을 것이다 :

  1. d [1] + 비용 [1] [2] = 2 < d [2] . d [2] = 2 이다.
  2. d [2] + 비용 [2] [3] = 5 < d [3] . d [3] = 5 이다.
  3. d [3] + 비용 [3] [4] = 7 < d [4] . d [4] = 5 이다.

첫 번째 반복은 소스 에서 다른 모든 노드까지 최단 경로를 찾았습니다. 1-> 2 , 3-> 4 , 2-> 3의 순서 가 가능하며, 2 회 반복 한 후 최단 경로를 제공합니다. 시퀀스를 정렬하는 방법에 관계없이이 예제에서 소스 에서 최단 경로를 찾는 데 3 번 이상 걸리지 않을 것이라는 결정을 내릴 수 있습니다.

최선의 경우 소스 로부터 최단 경로를 찾는 데 1 반복이 걸린다는 결론을 얻을 수 있습니다. 최악의 경우, 그것은 (V-1) 회 반복을 취할 것이기 때문에 우리는 이완 (V-1) 회 과정을 반복합니다.

그래프에서 음수주기 감지

이 예제를 이해하려면 여기 에서 찾을 수있는 Bellman-Ford 알고리즘에 대한 간단한 아이디어를 얻는 것이 좋습니다 .

Bellman-Ford 알고리즘을 사용하면 그래프에 음수 사이클이 있는지 감지 할 수 있습니다. 최단 경로를 찾으려면 그래프 (V-1) 시간의 모든 가장자리를 완화 해야합니다. 여기서 V 는 그래프의 정점 수입니다. 우리는 이미이 예제 에서 (V-1) 회 반복 이후에 반복 횟수가 아무리 많아도 d []를 업데이트 할 수 없다는 것을 보았습니다. 아니면 우리가 할 수 있을까요?

그래프에 음의 사이클이있는 경우, (V-1) 회 반복 한 후에도 d []를 업데이트 할 수 있습니다. 이것은 모든 반복에 대해 음수 사이클을 통과하면 항상 최단 경로의 비용이 감소하기 때문에 발생합니다. 이것이 Bellman-Ford 알고리즘이 반복 횟수를 (V-1)로 제한하는 이유입니다. 여기서 Dijkstra 's Algorithm 을 사용하면 무한 루프에 빠지게됩니다. 그러나 부정적인주기를 찾는 데 집중하십시오.

우리는 그래프를 가지고 있다고 가정 해 봅시다 :

예제 그래프

꼭지점 1소스선택해 봅시다. Bellman-Ford의 단일 소스 최단 경로 알고리즘을 그래프에 적용한 후 소스 에서 다른 모든 정점까지의 거리를 확인합니다.

Bellman Ford를 적용한 후

이것은 그래프가 (V-1) = 3 회 반복 된 것과 같은 모양입니다. 4 개의 가장자리가 있기 때문에 결과가되어야합니다. 최단 경로를 찾으려면 최대 3 번 반복해야합니다. 그래서 이것은 대답이거나 그래프에 음의 가중치 순환이 있습니다. 그것을 (V-1) 회 반복 한 후에, 우리는 마지막 반복을 한 번 더하고, 거리가 계속 감소하면 그래프에 음의 가중 사이클이 있음을 의미합니다.

예를 들어 우리는 체크하면 2-3, D [2] + 선정 [2] [3] 우리 D보다 1를 제공한다 [3]. 따라서 우리 그래프에는 음의주기가 있다고 결론을 내릴 수 있습니다.

그렇다면 우리는 어떻게 부정적인주기를 발견 할 수 있습니까? Bellman-Ford 절차에 약간 수정합니다 :

Procedure NegativeCycleDetector(Graph, source):
n := number of vertices in Graph
for i from 1 to n
    d[i] := infinity
end for
d[source] := 0
for i from 1 to n-1
    flag := false
    for all edges from (u,v) in Graph
        if d[u] + cost[u][v] < d[v]
            d[v] := d[u] + cost[u][v]
            flag := true
        end if
    end for
    if flag == false
        break
end for
for all edges from (u,v) in Graph
    if d[u] + cost[u][v] < d[v]
        Return "Negative Cycle Detected"
    end if
end for
Return "No Negative Cycle"

이것은 그래프에 음의주기가 있는지를 확인하는 방법입니다. 또한 Bellman-Ford 알고리즘을 수정하여 부정적인 사이클을 추적 할 수 있습니다.



Modified text is an extract of the original Stack Overflow Documentation
아래 라이선스 CC BY-SA 3.0
와 제휴하지 않음 Stack Overflow