#ifndef NDEBUG
#define NDEBUG
#endif
#define _CRT_SECURE_NO_WARNINGS
#ifdef __GNUC__
#include <bits/stdc++.h>
#include <ext/pb_ds/assoc_container.hpp>
#define unordered_map __fast_unordered_map
template<class Key, class Value, class Hash = std::hash<Key>>
using unordered_map = __gnu_pbds::gp_hash_table<Key, Value, Hash>;
#else
#include <iostream>
#include <fstream>
#include <vector>
#include <deque>
#include <set>
#include <map>
#include <unordered_map>
#include <list>
#include <array>
#include <cstdlib>
#include <stack>
#include <string>
#include <queue>
#include <chrono>
#include <functional>
#include <limits>
#include <cmath>
#include <algorithm>
#include <random>
#include <regex>
#include <tuple>
#include <numeric>
#include <cassert>
#include <utility>
#include <bitset>
#include <complex>
#include <iomanip>
#include <ostream>
#include <sstream>
#include <ctime>
unsigned int __builtin_popcount(unsigned int x)
{
int ret = 0;
while(x)
{
ret += x & 1;
x >>= 1;
}
return ret;
}
unsigned long long __builtin_popcountll(unsigned long long x)
{
int ret = 0;
while(x)
{
ret += x & 1LL;
x >>= 1LL;
}
return ret;
}
long long __gcd(long long a, long long b)
{
assert(a >= 0);
assert(b >= 0);
if (b == 0) return a;
long long ret = __gcd(b, a % b);
assert(ret);
return ret;
}
int __gcd(int a, int b)
{
assert(a >= 0);
assert(b >= 0);
if (b == 0) return a;
int ret = __gcd(b, a % b);
assert(ret);
return ret;
}
bool __builtin_sadd_overflow(int a, int b, int *res) { return false; }
bool __builtin_saddll_overflow(long long int a, long long int b, long long int *res) { return false; }
bool __builtin_ssub_overflow(int a, int b, int *res) { return false; }
bool __builtin_ssubll_overflow(long long int a, long long int b, long long int *res) { return false; }
bool __builtin_smul_overflow(int a, int b, int *res) { return false; }
bool __builtin_smulll_overflow(long long int a, long long int b, long long int *res) { return false; }
#endif
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef long double ld;
typedef unsigned short ushort;
const ll INFLL = 2 * (ll)1e18 + 100;
#define for0(i, n) for(int i = 0; i < n; ++i)
#define for1(i, n) for(int i = 1; i <= n; ++i)
#define pb push_back
#define mp make_pair
#define all(v) v.begin(), v.end()
#define V vector<int>
#define VP vector<pair<int, int> >
#define FASTIO ios_base::sync_with_stdio(0); cin.tie(0); cout.tie(0)
#define index INDEX
template<class T> ostream &operator<<(ostream& os, const vector<T>& v) {
if (v.empty()) return os;
for (std::size_t i = 0; i < v.size() - 1; ++i) os << v[i] << ' ';
return os << v.back();
}
template<class T> ostream &operator<<(ostream& os, const deque<T>& v) {
if (v.empty()) return os;
for (std::size_t i = 0; i < v.size() - 1; ++i) os << v[i] << ' ';
return os << v.back();
}
template<class T> ostream &operator<<(ostream& os, const set<T>& v) {
if (v.empty()) return os;
auto aux = v.end(); --aux;
for(auto it = v.begin(); it != aux; ++it)
{
os << *it << ' ';
}
return os << *aux;
}
template<class T> ostream &operator<<(ostream& os, const multiset<T>& v) {
if (v.empty()) return os;
auto aux = v.end(); --aux;
for (auto it = v.begin(); it != aux; ++it)
{
os << *it << ' ';
}
return os << *aux;
}
template<class L, class R> ostream &operator<<(ostream &os, const pair<L, R>& P) {
return os << P.first << " " << P.second;
}
template<class TH> void _dbg(const char *sdbg, TH h) { cerr << sdbg << " = " << h << '\n'; }
template<class TH, class... TA> void _dbg(const char *sdbg, TH h, TA... a) {
while (*sdbg != ',') cerr << *sdbg++;
cerr << " = " << h << ','; _dbg(sdbg + 1, a...);
}
#ifdef AJECC
#define debug(...) _dbg(#__VA_ARGS__, __VA_ARGS__)
#else
#define debug(...) (__VA_ARGS__)
#define cerr if(0)cout
#endif
auto rng = mt19937_64(chrono::steady_clock::now().time_since_epoch().count());
int generate_random() {
const int MAX_RANDOM = (int)20;
return uniform_int_distribution<unsigned int>(1, MAX_RANDOM)(rng);
}
#define int ll /// might modify this sometimes
#ifdef int
const int INFINT = INFLL;
#else
const int INFINT = 2 * (int)1e9 + 100;
#endif
const double PI = atan(1) * 4;
const double EPS = 1e-6;
const int SEED = (int)1e3 + 7;
const int MOD = (int)1e9 + 7;
const int NMAX = (int)3 * 1e6 + 5;
inline void hash_combine(std::size_t& seed) {}
template <typename T, typename... Rest>
inline void hash_combine(std::size_t& seed, const T& v, Rest... rest) {
std::hash<T> hasher;
seed ^= hasher(v) + 0x9e3779b9 + (seed<<6) + (seed>>2);
hash_combine(seed, rest...);
}
struct pair_hash {
template <class T1, class T2>
size_t operator() (const std::pair<T1, T2> &p) const {
#ifdef int
std::cout << "undef int!!!\n";
assert(false);
#endif
if (std::is_arithmetic<T1>::value && std::is_arithmetic<T2>::value && sizeof(T1) <= 4 && sizeof(T2) <= 4)
{
uint32_t val1 = *(uint32_t*)(&p.first);
uint32_t val2 = *(uint32_t*)(&p.second);
return (((size_t)val1 << 32LL) | val2);
}
auto h1 = std::hash<T1>{}(p.first);
auto h2 = std::hash<T2>{}(p.second);
size_t ret = 0;
hash_combine<T1>(ret, h1, h2);
return ret;
}
};
class directed_graph
{
public:
std::vector<std::vector<int>> graph;
std::vector<std::vector<std::pair<int, int>>> graph_costs;
size_t nodes_count = 0;
directed_graph(const size_t& nodes_count)
{
this->nodes_count = nodes_count;
graph.resize(nodes_count + 1, {});
graph_costs.resize(nodes_count + 1, {});
}
void add_edge(const int& source, const int& destination)
{
assert(source <= nodes_count);
assert(destination <= nodes_count);
graph[source].push_back(destination);
}
void add_cost(const int& source, const int& destination, const int& cost)
{
assert(source <= nodes_count);
assert(destination <= nodes_count);
graph_costs[source].push_back({ destination, cost });
}
std::vector<int> run_dijkstra(const int& source)
{
assert(source <= nodes_count);
std::priority_queue<std::pair<int, int>, std::vector<std::pair<int, int>>, std::greater<std::pair<int, int>>> heap;
heap.push({ 0, source });
std::vector<int> ret;
ret.resize(nodes_count + 1, INFINT);
while (!heap.empty())
{
int node = heap.top().second;
int cost = heap.top().first;
heap.pop();
if (ret[node] > cost)
{
ret[node] = cost;
for (const auto& next_node : graph_costs[node])
{
if (ret[next_node.first] > cost + next_node.second)
{
heap.push({ cost + next_node.second, next_node.first });
}
}
}
}
return ret;
}
std::vector<int> run_bellman(const int& source)
{
std::vector<int> cycle_verification(nodes_count + 1, 0);
assert(source <= nodes_count);
std::vector<int> ret;
ret.resize(nodes_count + 1, INFINT);
std::queue<int> q;
q.push(source);
ret[source] = 0;
while (!q.empty())
{
int node = q.front();
q.pop();
cycle_verification[node]++;
if (cycle_verification[node] > nodes_count)
{
return {};
}
for (const auto& next_node : graph_costs[node])
{
if (ret[next_node.first] > ret[node] + next_node.second)
{
ret[next_node.first] = ret[node] + next_node.second;
q.push(next_node.first);
}
}
}
return ret;
}
std::vector<std::vector<int>> run_floyd()
{
std::vector<std::vector<int>> ret(nodes_count + 1, std::vector<int>(nodes_count + 1, INFINT));
for (int node = 1; node <= nodes_count; node++)
{
ret[node][node] = 0;
for (const auto& other_node : graph_costs[node])
{
ret[node][other_node.first] = other_node.second;
}
}
for (int pivot = 1; pivot <= nodes_count; pivot++)
{
for (int i = 1; i <= nodes_count; i++)
{
for (int j = 1; j <= nodes_count; j++)
{
if (ret[i][j] > ret[i][pivot] + ret[pivot][j])
{
ret[i][j] = ret[i][pivot] + ret[pivot][j];
}
}
}
}
return ret;
}
};
int32_t main() {
FASTIO; /// disable for interactive
#ifdef AJECC
double START_PROGRAM = clock();
#endif
assert(sizeof(size_t) == 8);
freopen("royfloyd.in", "r", stdin);
freopen("royfloyd.out", "w", stdout);
int n;
cin >> n;
directed_graph graph(n);
for1(i, n)
{
for1(j, n)
{
int cost;
cin >> cost;
if (cost != 0)
{
graph.add_edge(i, j);
graph.add_cost(i, j, cost);
}
}
}
auto floyd = graph.run_floyd();
for (int i = 1; i <= n; i++)
{
for (int j = 1; j <= n; j++)
{
cout << floyd[i][j] << ' ';
}
cout << '\n';
}
#ifdef AJECC
double END_PROGRAM = clock();
double ELAPSED_TIME = (END_PROGRAM - START_PROGRAM) / CLOCKS_PER_SEC;
cerr << "\n\nElapsed Time: " << ELAPSED_TIME * 1000 << "ms\n";
#endif
return 0;
}