All-Pairs Shortest Paths

1
2
3
4
5
6
7
8
{
    {},
    {0, 0, 3, 8, INF, -4},
    { 0,INF,0,INF,1,7 },
    { 0,INF ,4,0,INF ,INF },
    {0 , 2, INF ,-5, 0 ,INF },
    { 0,INF ,INF ,INF ,6,0 }
};
1
2
typedef std::vector<std::vector<int>>  Matrix;
// must NxN
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
const int NIL = 0;
const int INF = 100000000;

void PRINT_ALL_PAIRS_SHORTEST_PATH(Matrix pi, int i, int j)
{
    if (i == j)
        std::cout << ' ' << i << ' ';
    else if (pi[i][j] == NIL)
    {
        std::cout << "no path from " << i << " to " << j << " exists" << std::endl;
    }
    else
    {
        PRINT_ALL_PAIRS_SHORTEST_PATH(pi, i, pi[i][j]);
        std::cout << ' ' << j << ' ';
    }
}
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
#include<iomanip>
void print_matrix(Matrix& m)
{
    const int n = m.size();

    for (int i = 1; i < n; i++)
    {
        for (int j = 1; j < n; j++)
        {
            if(m[i][j] == INF)
                std::cout << "INF" << ' ';
            else
                std::cout <<std::setw(3)<< m[i][j] << ' ';

        }
        std::cout << '\n';
    }
    std::cout << '\n' << '\n';
}

25.1 Shortest paths and matrix multiplication

$O(V^3)$

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
Matrix EXTEND_SHORTEST_PATHS(Matrix& L, Matrix& W)
{
    const int n = L.size();

    Matrix L_prime(n, std::vector<int>(n, INF));
    for(int i = 1; i < n; i++)
    {
        for (int j = 1; j < n; j++)
        {

            for (int k = 1; k < n; k++)
            {
                L_prime[i][j] = (L_prime[i][j] < L[i][k] + W[k][j] ?  L_prime[i][j] : L[i][k] + W[k][j]);
            }

        }
    }
    return L_prime;
}

총 $O(V^4)$

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
//nxn 1~n
MatrixSLOW_ALL_PAIRS_SHORTEST_PATHS(Matrix& W)
{
    const int n = W.size();

    std::vector<Matrix> L(n, Matrix(n, std::vector<int>(n)));
    L[1] = W;
    for (int m = 2; m < n; m++)
    {
        L[m] = EXTEND_SHORTEST_PATHS(L[m - 1], W);
    }
    return L[n-1];
}

총 $O(V^3 \log (V))$

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
MatrixFASTER_ALL_PAIRS_SHORTEST_PATHS(Matrix& W)
{
    const int n = W.size() - 1;

    int a = 1;
    while (a < n)
    {
        a = a * 2;
    }
    std::vector<Matrix> L(a+1, Matrix(n, std::vector<int>(n)));
    L[1] = W;

    int m = 1;
    while(m < n - 1)
    {
        L[2*m] = EXTEND_SHORTEST_PATHS(L[m], L[m]);
        m = m*2;
    }
    return  L[m];
}

//25.1-6

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
void set_pi(Matrix &W, std::vector<std::vector<int >> &L, Matrix& pi)
{
    const int n = L.size();
    for (int i = 1; i < n; i++)
    {
        for (int j = 1; j < n ;j++)
        {
            for (int k = 1; k < n; k++)
            {
                if ((L[i][j] - L[i][k]) == W[k][j])
                {
                    if (W[k][j] != 0 && i!=j)
                    {
                        pi[i][j] = k;
                    }
                }
            }
        }
    }
}

//25.7 전체 다시 짜기

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
//25.1-7
void EXTEND_SHORTEST_PATHS_pi(Matrix& L, 
    Matrix& W, Matrix& pi,
    Matrix* __L , Matrix *___pi
)
{
    const int n = L.size();
    //Matrix L_prime;
    //L_prime.assign(n, std::vector<int>(n, INF));
    for (int i = 1; i < n; i++)
    {
        for (int j = 1; j < n; j++)
        {

            for (int k = 1; k < n; k++)
            {
                if ((*__L)[i][j] > L[i][k] + W[k][j])
                {
                    (*__L)[i][j] = (L[i][k] + W[k][j]);
                    (*___pi)[i][j] = k;
                }
            }

        }
    }
    //return L_prime;
}

//nxn 1~n
void SLOW_ALL_PAIRS_SHORTEST_PATHS_pi(const Matrix& W, 
    Matrix *out_pi, Matrix *out_L)
{
    const int n = W.size() - 1;

    std::vector<Matrix> L(n + 1, Matrix(n + 1, std::vector<int>(n + 1, INF)));
    std::vector<Matrix> pi(n + 1, Matrix(n + 1, std::vector<int>(n + 1, INF)));

    L[1] = W;
    for (int m = 2; m < n; m++)
    {
        EXTEND_SHORTEST_PATHS_pi(L[m - 1], W, pi[m - 1], &L[m], &pi[m]);
    }
    out_L->swap(L[n - 1]);
    out_pi->swap(pi[n - 1]);
}

25.1-8 space requirement Theta(n^2)

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
Matrix FASTER_ALL_PAIRS_SHORTEST_PATHS(Matrix& W)
{
    const int n = W.size() - 1;

    Matrix A(n + 1, std::vector<int>(n + 1))
    Matrix B(W);

    int m = 1;

    while (m < n - 1)
    {
        A = EXTEND_SHORTEST_PATHS(B, B);
        m = m * 2;
        if (m >= n - 1)
        {
            return A;
        }

        B = EXTEND_SHORTEST_PATHS(A, A);
        m = m * 2;
    }
    return  B;
}

25.1-9 25.1-8에 이어서. no consider overflow;

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
Matrix FASTER_ALL_PAIRS_SHORTEST_PATHS(const Matrix& W)
{
    const int n = W.size() - 1;

    Matrix A = W, B = W, C = W ,D = W;

    int m = 1;

    while (1)
    {
        A = EXTEND_SHORTEST_PATHS(B, B);
        m = m * 2;
        if (m > n - 1)
        {
            C = A;
            break;
        }

        B = EXTEND_SHORTEST_PATHS(A, A);
        m = m * 2;
        if (m > n - 1)
        {
            C = B;
            break;
        }
    }
    D = EXTEND_SHORTEST_PATHS(C, C);

    print_matrix(C);
    print_matrix(D);


    bool chk_nwc = 0;
    for (int i = 1; i <= n && !chk_nwc; i++)
    {
        for (int j = 1; j <= n && !chk_nwc; j++)
        {
            if (C[i][j] != D[i][j])
            {
                chk_nwc = true;
            }
        }
    }

    if (chk_nwc)
        std::cout << "the input graph contains a negative-weight cycle" << std::endl;

    return C;
}

25.2 The Floyd-Warshall algorithm

n = n+1

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
MatrixFLOYD_WARSHALL(const Matrix& W)
{
    const int n = W.size();
    std::vector<Matrix> D(n, Matrix(n, std::vector<int>(n)));
    D[0] = W;
    for(int k = 1 ; k <= n  ;k++)
    {
        for(int i = 1 ; i <= n ; i++)
        {
            for(int j = 1 ; j <= n ;j++)
            {
                D[k][i][j] = (D[k-1][i][j] < D[k-1][i][k] + D[k-1][k][j] ?  D[k-1][i][j] : D[k-1][i][k] + D[k-1][k][j]);
            }
        }
    }
    return  D[n-1];
}

Graph is nxn matrix

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
Matrix TRANSITIVE_CLOSURE(Matrix& G)
{
    const int n = G.size();
    std::vector<Matrix> T(n, Matrix(n, std::vector<int>(n)));

    for (int i = 1; i < n; i++)
    {
        for (int j = 1; j < n; j++)
        {
            if ((i == j) || (G[i][j] != 0))
            {
                T[0][i][j] = 1;

            }
            else
            {
                T[0][i][j] = 0;
            }
        }
    }
    for (int k = 1; k < n; k++)
    {
        for (int i = 1; i < n; i++)
        {
            for (int j = 1; j < n; j++)
            {
                T[k][i][j] = T[k - 1][i][j] | (T[k - 1][i][k] & T[k - 1][k][j]);
            }
        }
    }
    return  T[n - 1];
}

25.2-3 25.2-4에 이어서.

공간복잡도 $O(n^3)$

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
Matrix FLOYD_WARSHALL_apostrophe_pi(cosnt Matrix &W, Matrix & out_pi )
{
    const int n = W.size() - 1;
    Matrix D(W);
    std::vector<Matrix> pi_prime(n + 1, Matrix(n + 1, std::vector<int>(n + 1)));

    for (int k = 0; k <= n; k++)
    {
        for (int i = 0; i <= n; i++)
        {
            for (int j = 0; j <= n; j++)
            {
                if ((i == j) || (pi_prime[k][i][j] == INF))
                {
                    pi_prime[k][i][j] = NIL;
                }
                else
                {
                    pi_prime[k][i][j] = k;
                }
            }
        }
    }


    for (int i = 1; i <= n; i++)
    {
        for (int j = 1; j <= n; j++)
        {
            if ((D[i][j] != INF)&&(i != j))
            {
                pi_prime[0][i][j] = i;
            }
        }
    }

    print_matrix(pi_prime[0]);

    for (int k = 1; k <= n; k++)
    {
        for (int i = 1; i <= n; i++)
        {
            for (int j = 1; j <= n; j++)
            {
                if (D[i][j] > D[i][k] + D[k][j])
                {
                    D[i][j] = D[i][k] + D[k][j];
                    pi_prime[k][i][j] = pi_prime[k - 1][k][j];
                }
                else
                {
                    pi_prime[k][i][j] = pi_prime[k - 1][i][j];
                }
            }
        }
    }
    out_pi.swap(pi_prime[n]);
    return D;
}

공간복잡도 $O(n^2)$

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
Matrix FLOYD_WARSHALL_apostrophe_pi(const Matrix& W, Matrix& out_pi )
{
    const int n = W.size()-1;
    Matrix D = W;
    Matrix pi_prime(n + 1, std::vector<int>(n + 1));

    for (int i = 1; i <= n; i++)
    {
        for (int j = 1; j <= n; j++)
        {
            if ((W[i][j] != INF) && (i != j))
            {
                pi_prime[i][j] = i;
            }
        }
    }
    print_matrix(pi_prime);

    for (int k = 1; k <= n; k++)
    {
        for (int i = 1; i <= n; i++)
        {
            for (int j = 1; j <= n; j++)
            {
                if (D[i][j] > D[i][k] + D[k][j])
                {
                    D[i][j] = D[i][k] + D[k][j];
                    pi_prime[i][j] = pi_prime[k][j];
                }
            }
        }
    }
    out_pi.swap(pi_prime);
    return  D;
}

25.2-4

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
Matrix FLOYD_WARSHALL_apostrophe(const Matrix& W)
{
    const int n = W.size();
    Matrix D(W);

    for (int k = 1; k < n; k++)
    {
        for (int i = 1; i < n; i++)
        {
            for (int j = 1; j < n; j++)
            {
                D[i][j] = (D[i][j] < D[i][k] + D[k][j] ? D[i][j] : D[i][k] + D[k][j]);
            }
        }
    }
    return  D;
}

25.3 Johnson's algorithm for sparse graphs

인접리스트 Graph+W행렬과 인접리스트 가중치 그래프 각각으로 짜여져있다

O(VElgV)

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
void INITIALIZE_SINGLE_SOURCE(const Graph& Graph,
    std::vector<int>& Distance, int s)
{
    std::fill(Distance.begin(), Distance.begin() + Graph.size(), INF);
    Distance[s] = 0;
}


void BF_RELAX(int u, int v, int w, std::vector<int>& Distance)
{
    if (Distance[v] > Distance[u] + w)
    {
        Distance[v] = Distance[u] + w;
    }
}

//for johnson's alg
bool BELLMAN_FORD(const Graph& Graph, 
    const Matrix& W,
    std::vector<int> &Distance, int s)
{
    INITIALIZE_SINGLE_SOURCE(Graph, Distance, s);
    const std::size_t n = Graph.size() - 1;

    for (std::size_t i = 1; i <= n; i++)// 간선 u v w = Graph[v][]
    {
        for (std::size_t u = 0; u <= n; u++)
        {
            for (int v : Graph[u])
            {
                int w = W[u][v];
                BF_RELAX(u, v, w, Distance);
            }
        }
    }

    for (std::size_t u = 1; u <= n ; u++)
    {
        for (int v : Graph[u])
        {
            if ((Distance[v] > Distance[u] + W[u][v]) && Distance[u] != INF)
            {
                Distance[v] = -1;
                return false;
            }
        }
    }
    return true;
}

void DIJK_RELAX(int u, int v, int w, std::vector<int >& Distance,
    std::priority_queue<
        std::pair<int, int>,
        std::vector<std::pair<int, int>>,
        std::greater<std::pair<int, int>> >& PQ)
{
    if ((Distance[u] != INF) && (Distance[v] > Distance[u] + w))
    {
        Distance[v] = Distance[u] + w;
        //predecessor_subgraph[v] = u;
        PQ.push(std::make_pair(Distance[v], v));
    }
}

void DIJKSTRA(const Graph& Graph,
    Matrix& W,
    std::vector<int> &Distance, int s)
{
    INITIALIZE_SINGLE_SOURCE(Graph,Distance, s);
    std::priority_queue<std::pair<int, int>, std::vector<std::pair<int, int>>, std::greater<std::pair<int, int>> > PQ; //정점의 거리, 정점
    for (std::size_t i = 1; i < Graph.size(); i++)
    {
        PQ.push(std::make_pair(Distance[i], i));
    }

    while (!PQ.empty())
    {
        int u = PQ.top().second;
        PQ.pop();
        for (int v : Graph[u])
        {
            DIJK_RELAX(u, v, W[u][v], Distance,PQ);
        }
    }
}


Matrix JOHNSON(const Matrix& Graph,
    Matrix& W
)
{//
    Matrix D(n + 1, std::vector<int>(n + 1));
    Matrix G_apostrophe(Graph);
    const std::size_t n = Graph.size() - 1;

    for (std::size_t i = 1; i <= n; i++)
    {
        W[0].resize(n + 1);
        G_apostrophe[0].push_back(i);
    }

    std::vector<int > Distance(n + 1); // and h(x)

    if (BELLMAN_FORD(G_apostrophe,W ,Distance,0) == false)
    {
        std::cout << "the input graph contains a negative-weight cycle" << std::endl;
    }
    else
    {

        std::vector<int> h = Distance;
        Matrix W_het(W);        
        Matrix D_het(n + 1 std::vector<int>(n + 1));

        for (std::size_t u = 1; u <= n; u++)
        {
            for(int v : Graph[u])
            {
                W_het[u][v] += (h[u] - h[v]);
            }
        }
        for (std::size_t u = 1; u <= n; u++)
        {
            DIJKSTRA(Graph, W_het, D_het[u], u );

            for (std::size_t v = 1; v <= n; v++)
            {
                D[u][v] = D_het[u][v] + h[v] - h[u];
            }
        }
    }
    return D;
}

pair(정점,가중치) 가중치 인접그래프,

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
void INITIALIZE_SINGLE_SOURCE(std::vector<std::vector<std::pair<int, int>>>& Graph,
    std::vector<int>& Distance, int s)
{
    for (std::size_t i = 1; i < Graph.size(); i++)
    {
        Distance[i] = INF;
    }
    Distance[s] = 0;
}


void BF_RELAX(int u, int v, int w, std::vector<int>& Distance)
{
    if (Distance[v] > Distance[u] + w)
    {
        Distance[v] = Distance[u] + w;
    }
}


bool BELLMAN_FORD(std::vector<std::vector<std::pair<int, int>>>& Graph, 
    std::vector<int> &Distance, int s)
{
    INITIALIZE_SINGLE_SOURCE(Graph, Distance, s);
    const int n = Graph.size() - 1;

    for (std::size_t i = 1; i <= n; i++)// 간선 u v w = Graph[v][]
    {
        for (std::size_t u = 0; u <= n; u++)
        {
            const int sub_size = Graph[u].size();
            for (std::size_t j = 0; j < sub_size; j++)
            {
                int v = Graph[u][j].first;
                int w = Graph[u][j].second;
                BF_RELAX(u, v, w, Distance);
            }
        }
    }

    for (std::size_t u = 1; u <= n ; u++)
    {
        const int sub_size = Graph[u].size();
        for (std::size_t j = 0; j < sub_size; j++)
        {
            int v = Graph[u][j].first;
            if ((Distance[v] > Distance[u] + Graph[u][j].second) && Distance[u] != INF)
            {
                Distance[v] = -1;
                return false;
            }
        }
    }
    return true;
}


void DIJK_RELAX(int u, int v, int w, std::vector<int> &Distance, 
    std::priority_queue<
        std::pair<int, int>, 
        std::vector<std::pair<int, int>>, 
        std::greater<std::pair<int, int>> > &PQ)
{
    if ((Distance[u] != INF) && (Distance[v] > Distance[u] + w))
    {
        Distance[v] = Distance[u] + w;
        PQ.push(std::make_pair(Distance[v], v));
    }
}


void DIJKSTRA(std::vector<std::vector<std::pair<int, int>>>& Graph,
    std::vector<int> &Distance, int s)
{
    INITIALIZE_SINGLE_SOURCE(Graph,Distance, s );
    std::priority_queue<std::pair<int, int>, std::vector<std::pair<int, int>>, std::greater<std::pair<int, int>> > PQ; //정점의 거리, 정점
    for (int i = 1; i < Graph.size(); i++)
    {
        PQ.push(std::make_pair(Distance[i], i));
    }

    while (!PQ.empty())
    {
        int u = PQ.top().second;
        PQ.pop();
        for (int v = 0; v < Graph[u].size(); v++)
        {
            DIJK_RELAX(u, Graph[u][v].first, Graph[u][v].second, Distance,PQ);
        }
    }
}

//graph pair(정점,가중치)
Matrix JOHNSON(std::vector<std::vector<std::pair<int, int>>>& Graph
)
{//Matrix &W
    Matrix D(n + 1, std::vector<int>(n + 1));
    std::vector<std::vector<std::pair<int, int>>> G_apostrophe(Graph);
    const int n = Graph.size()-1;

    for (int i = 1; i <= n; i++)
    {
        G_apostrophe[0].push_back(std::make_pair(i, 0));
    }

    std::vector<int > Distance(n + 1); // and h(x)

    if (BELLMAN_FORD(G_apostrophe, Distance,0) == false)
    {
        std::cout << "the input graph contains a negative-weight cycle" << std::endl;
    }
    else
    {
        std::vector<int> h(Distance);
        std::vector<std::vector<std::pair<int, int>>> Graph_het = Graph;

        Matrix D_het(n + 1, std::vector<int>(n + 1));

        for (int i = 1; i <= n; i++)
        {
            const int sub_size = Graph_het[i].size();
            for (int j = 0; j < sub_size; j++)
            {
                Graph_het[i][j].second += (h[i] - h[Graph_het[i][j].first]);
            }
        }

        for (int u = 1; u <= n; u++)
        {
            DIJKSTRA(Graph_het, D_het[u], u );
            for (int v = 1; v <= n; v++)
            {
                D[u][v] = D_het[u][v] + h[v] - h[u];
            }
        }
    }

    return D;
}