Cod sursa(job #2971710)

Utilizator HandoMihnea-Vicentiu Hando Data 27 ianuarie 2023 21:23:42
Problema Floyd-Warshall/Roy-Floyd Scor 100
Compilator cpp-64 Status done
Runda Arhiva educationala Marime 4.71 kb
#include <bits/stdc++.h>
#include <ext/pb_ds/assoc_container.hpp>
#include <ext/pb_ds/tree_policy.hpp>

#define ar array
#define vt vector
#define pq priority_queue
#define pu push
#define pub push_back
#define em emplace
#define emb emplace_back

#define all(x) x.begin(), x.end()
#define allr(x) x.rbegin(), x.rend()
#define allp(x, l, r) x.begin() + l, x.begin() + r
#define len(x) (int)x.size()

using namespace std;
using namespace __gnu_pbds;

using ll = long long;
using ld = long double;
using ull = unsigned long long;

template <class T, size_t N>
void re(array <T, N>& x);
template <class T> 
void re(vt <T>& x);

template <class T> 
void re(T& x) {
    cin >> x;
}

template <class T, class... M> 
void re(T& x, M&... args) {
    re(x); re(args...);
}

template <class T> 
void re(vt <T>& x) {
    for(auto& it : x)
        re(it);
}

template <class T, size_t N>
void re(array <T, N>& x) {
    for(auto& it : x)
        re(it);
}

template <class T, size_t N>
void wr(array <T, N> x);
template <class T> 
void wr(vt <T> x);

template <class T> 
void wr(T x) {
    cout << x;
}

template <class T, class ...M>  void wr(T x, M... args) {
    wr(x), wr(args...);
}

template <class T> 
void wr(vt <T> x) {
    for(auto it : x)
        wr(it, ' ');
}

template <class T, size_t N>
void wr(array <T, N> x) {
    for(auto it : x)
        wr(it, ' ');
}


inline void Open(const string Name) {
    #ifndef ONLINE_JUDGE
        (void)!freopen((Name + ".in").c_str(), "r", stdin);
        (void)!freopen((Name + ".out").c_str(), "w", stdout);
    #endif
}

void solve() {
    const int INF = 2e9;
    int n; re(n);
    vt <vt <int>> a(n, vt <int>(n)), d = a; re(a);

    /* The key idea of the algorithm is to partition the process of finding 
       the shortest path between any two vertices to several incremental phases.

       Let us number the vertices starting from 1 to n. The matrix of distances is d[][]

       Before the k-th phase (k = 1...n), d[i][j] for any vertices i and j stores the length of the
       shortest path between the vertex i and vertex j, which contains only the vertices {1, 2, ..., k - 1}
       as internal vertices in the path. 

       In other words, before the k-th phase the value of d[i][j] is equal to the length of the shortest
       path form vertex i to the vertex j formed with vertices with labels less than k (the beggining and end of the path are not restricted by this property)

       It is easy to make sure that this property holds for the first phase. For k = 0, we fill the matrix with
       d[i][j] = w_{i,j}; if there exists an edge between i and j with weight w_{i, j} and d[i][j] = INF if the edge
       doesn't exist. 
    */

    for (int i = 0; i < n; ++i)
        for (int j = 0; j < n; ++j)
            d[i][j] = (a[i][j] == 0? INF : a[i][j]);

    /* Suppose now that we are in the k-th phase, and we want to compute d[][] so that it meets the req.
    for the (k + 1)-th phase. We have to fix the distance for some vertices (i, j). There are two fundamentally different cases:
        
        * The shortest path from i to j with internal vertices from the set {1, 2, ..., k} coincides with the shortest path
        with internal vertices from the set {1, 2, ..., k - 1}.
        
        * The shortest path with internal vertices from {1, 2, ..., k} is shorter =>
        This means that a new path passes through the vertex k, namely we can split the shortest path between i
        and j into two paths: the path between i and k, and the path between k and j. it is clear that both of this paths
        will only use internal vertices {1, 2, ..., k - 1} and the shortest such paths in that respect. 
        Therefore we can compute the lenght of the shortest path between i and j as d[i][k] + d[k][j].

        Combining these two cases we find that we can recalculate the length of all pairs (i, j) in the k-th phase in the following way:
        
        d_new[i][j] = min(d[i][j], d[i][k] + d[k][j]);

        As a remark: we don't need d_new[][] all changes can be made directly in the matrix d[][]
    */

    for (int k = 0; k < n; ++k)
        for (int i = 0; i < n; ++i)
            for (int j = 0; j < n; ++j)
                if(i != j and d[i][k] < INF and d[k][j] < INF) {
                    d[i][j] = min(d[i][j], d[i][k] + d[k][j]);
                }

    for (int i = 0; i < n; ++i) {
        for (int j = 0; j < n; ++j)
            wr(d[i][j] == INF? 0 : d[i][j], ' ');
        wr('\n');
    }

}

int main() {
    ios_base::sync_with_stdio(false);
    cin.tie(nullptr);

    Open("royfloyd");

    int t = 1;
    for(;t;t--) {
        solve();
    }
    
    return 0;
}