// hilo

#include <bits/stdc++.h>

#define all(x) (x).begin(), (x).end()
#define rall(x) (x).rbegin(), (x).rend()
#define cast(type, data) static_cast <type>(data)

typedef long long ll;
typedef unsigned long long ull;
typedef long double ld;

std::string to_string(const std::string& s) { return '"' + s + '"'; }
std::string to_string(const char* s) { return to_string((std::string)s); }
std::string to_string(const bool& b) { return (b ? "true" : "false"); }
std::string to_string(const char& c) { return (std::string)"'" + c + "'"; }
std::string to_string(const std::vector <bool>& v) { if (v.empty()) { return "{ }"; } std::string ret = "{" + to_string(v.front()); for (int i = 1; i < cast(int, v.size()); i++) { ret += ", " + to_string(v[i]); } return ret + "}"; }
template <typename A> std::string to_string(A x) { return std::to_string(x); }
template <typename A, typename B> std::string to_string(std::pair<A, B> p) { return "(" + to_string(p.first) + ", " + to_string(p.second) + ")"; }
template <typename A> std::string to_string(const std::vector <A>& v) { if (v.empty()) { return "{ }"; } std::string ret = "{" + to_string(v.front()); for (int i = 1; i < cast(int, v.size()); i++) { ret += ", " + to_string(v[i]); } return ret + "}"; }
template <typename A> std::string to_string(const std::set <A>& st) { if (st.empty()) { return "[empty]"; } auto it = st.begin(); std::string ret = "[" + to_string(*it); it++; for (; it != st.end(); it++) { ret += ", " + to_string(*it); } return ret + "]"; }
template <typename A, typename B> std::string to_string(const std::set <A, B>& st) { if (st.empty()) { return "[empty]"; } auto it = st.begin(); std::string ret = "[" + to_string(*it); it++; for (; it != st.end(); it++) { ret += ", " + to_string(*it); } return ret + "]"; }
template <typename A> std::string to_string(const std::unordered_set <A>& st) { if (st.empty()) { return "[empty]"; } auto it = st.begin(); std::string ret = "[" + to_string(*it); it++; for (; it != st.end(); it++) { ret += ", " + to_string(*it); } return ret + "]"; }
template <typename A, typename B> std::string to_string(const std::map <A, B>& mp) { if (mp.empty()) { return "[empty]"; } auto it = mp.begin(); std::string ret = "[(" + to_string((*it).first) + ": " + to_string((*it).second) + ")"; it++; for (; it != mp.end(); it++) { ret += ", (" + to_string((*it).first) + ": " + to_string((*it).second) + ")"; } return ret + "]"; }
template <typename A, typename B, typename C> std::string to_string(const std::map <A, B, C>& mp) { if (mp.empty()) { return "[empty]"; } auto it = mp.begin(); std::string ret = "[(" + to_string((*it).first) + ": " + to_string((*it).second) + ")"; it++; for (; it != mp.end(); it++) { ret += ", (" + to_string((*it).first) + ": " + to_string((*it).second) + ")"; } return ret + "]"; }
template <typename A, typename B> std::string to_string(const std::unordered_map <A, B>& mp) { if (mp.empty()) { return "[empty]"; } auto it = mp.begin(); std::string ret = "[(" + to_string((*it).first) + ": " + to_string((*it).second) + ")"; it++; for (; it != mp.end(); it++) { ret += ", (" + to_string((*it).first) + ": " + to_string((*it).second) + ")"; } return ret + "]"; }
template <typename A> std::string to_string(const std::queue <A>& q) { if (q.empty()) { return "[empty]"; } std::queue <A> bckp = q; std::string ret = "[" + to_string(bckp.front()); bckp.pop(); while (!bckp.empty()) { A tp = bckp.front(); bckp.pop(); ret += ", " + to_string(tp); } return ret + "]"; }
template <typename A> std::string to_string(const std::priority_queue <A>& pq) { if (pq.empty()) { return "[empty]"; } std::priority_queue <A> bckp = pq; std::string ret = "[" + to_string(bckp.top()); bckp.pop(); while (!bckp.empty()) { A tp = bckp.top(); bckp.pop(); ret += ", " + to_string(tp); } return ret + "]"; }
template <typename A, typename B> std::string to_string(const std::priority_queue <A, std::vector <A>, B>& pq) { if (pq.empty()) { return "[empty]"; } std::priority_queue <A, std::vector <A>, B> bckp = pq; std::string ret = "[" + to_string(bckp.top()); bckp.pop(); while (!bckp.empty()) { A tp = bckp.top(); bckp.pop(); ret += ", " + to_string(tp); } return ret + "]"; }
template <typename A> std::string to_string(const std::stack <A>& stck) { if (stck.empty()) { return "[empty]"; } std::stack <A> bckp = stck; std::string ret = "[" + to_string(bckp.top()); bckp.pop(); while (!bckp.empty()) { A tp = bckp.top(); bckp.pop(); ret += ", " + to_string(tp); } return ret + "]"; }
template <typename A> std::string to_string(const std::deque <A>& dq) { if (dq.empty()) { return "[empty]"; } std::deque <A> bckp = dq; std::string ret = "[" + to_string(bckp.front()); bckp.pop_front(); while (!bckp.empty()) { A tp = bckp.front(); bckp.pop_front(); ret += ", " + to_string(tp); } return ret + "]"; }

void debug_out() { std::cerr << std::endl; }
template <typename H, typename... T> void debug_out(H h, T... t) { std::cerr << "\033[37m " << to_string(h) << "\033[0m"; debug_out(t...); }

void debum_out() { std::cerr << std::endl; }
void debum_tab(const int cnt = 1) { for (int i = 0; i < cnt; i++) { std::cerr << "  "; } }
template <typename T> void debum_out(T t) { for (auto it = t.begin(); it != t.end(); it++) { debum_tab(1); std::cerr << "\033[37m[ " << to_string(*it) << " ]\033[0m" << std::endl; } }

#ifndef ONLINE_JUDGE
#define debug(...) std::cerr << "\033[37m[" << #__VA_ARGS__ << "]:\033[0m", debug_out(__VA_ARGS__)
#define debum(...) std::cerr << "\033[37m[" << #__VA_ARGS__ << "]:\033[0m\n", debum_out(__VA_ARGS__)
#else
#define debug(...)
#define debum(...)
#endif

void prep();
void solv(const int curt);

const bool isT = false;

int main() {
	std::ios::sync_with_stdio(0); std::cin.tie(0);
	
	prep();
	
	int t = 1; if (isT) { std::cin >> t; }
	for (int i = 1; i <= t; i++) { solv(i); }
	
	return 0;
}

void prep() {
	std::cout.tie(0);
}

struct Edge { int u, v; };
std::vector <Edge> ed;
const ll mod = 998244353;
const int inf = 1 << 30;
int n, m;
std::vector <std::vector <int>> g;
std::vector <std::vector <int>> am;
std::vector <std::vector <int>> dist;
std::vector <std::vector <ll>> ans;

void FW() {
	for (int i = 0; i < n; i++)
		dist[i][i] = 0;
	for (const Edge& e : ed)
		dist[e.v][e.u] = dist[e.u][e.v] = 1;
	for (int k = 0; k < n; k++)
		for (int i = 0; i < n; i++)
			for (int j = 0; j < n; j++)
				if (dist[i][k] != inf && dist[k][j] != inf)
					dist[i][j] = std::min(dist[i][j], dist[i][k] + dist[k][j]);
}

bool is_candidate(int u, int v) {
	if (u == v) return true;
	int cnt = 0;
	for (int i = 0; i < n; i++)
		cnt += dist[u][i] + dist[i][v] == dist[u][v];
	return cnt == dist[u][v] + 1;
}

void find(int u, int v, const std::vector <std::pair <int, int>>& edges) {
	ans[u][v] = 1;
	std::vector <ll> cnt(n, 0);
	cnt[u] = 1;
	for (const auto p : edges) {
		int from = p.second, to = p.first;
		if (dist[to][u] + dist[to][v] == dist[u][v]) {
			cnt[to] = 1;
			continue;
		}
		cnt[to] += dist[v][from] + 1 == dist[v][to];
	}
	for (ll x : cnt) ans[u][v] = (ans[u][v] * x) % mod;
	ans[v][u] = ans[u][v];
}

void solv(const int curt) {
	
	std::cin >> n >> m;
	g.resize(n);
	am.resize(n, std::vector <int> (n, 0));
	dist.resize(n, std::vector <int> (n, inf));
	ans.resize(n, std::vector <ll> (n, 0));
	for (int i = 0; i < m; i++) {
		int u, v; std::cin >> u >> v; u--, v--;
		g[u].push_back(ed.size());
		g[v].push_back(ed.size());
		ed.push_back({ u, v });
		am[u][v] = am[v][u] = 1;
	}
	FW();
	for (int i = 0; i < n; i++) {
		std::vector <std::pair <int, int>> edges;
		for (const Edge& e : ed) {
			int from = dist[i][e.v] < dist[i][e.u] ? e.v : e.u;
			int to = e.v ^ e.u ^ from;
			if (dist[i][from] + 1 == dist[i][to])
				edges.emplace_back(to, from);
		}
		//std::vector <std::vector <int>> dst;
		//std::vector <std::pair <int, int>> edges;
		//for (int k = 0; k < n; k++) {
			//if ((int)dst.size() < dist[i][k] + 1)
				//dst.resize(dist[i][k] + 1);
			//dst[dist[i][k]].push_back(k);
		//}
		//for (int j = 1; j < (int)dst.size(); j++) {
			//for (int u : dst[j]) {
				//for (int x : g[u]) {
					//int v = ed[x].u ^ ed[x].v ^ u;
					//if (dist[v][i] + 1 == dist[u][i])
						//edges.emplace_back(u, v);
				//}
			//}
		//}
		for (int j = i; j < n; j++) {
			if (is_candidate(i, j))
				find(i, j, edges);
		}
	}
	for (int i = 0; i < n; i++)
		for (int j = 0; j < n; j++)
			std::cout << ans[i][j] << " \n"[j == n - 1];
	
}
