#include <bits/stdc++.h>
using namespace std;
//#define cerr if (false) cerr
#define db(x) cerr << #x << "=" << x << endl
#define db2(x, y) cerr << #x << "=" << x << "," << #y << "=" << y << endl
#define db3(x, y, z) cerr << #x << "=" << x << "," << #y << "=" << y << "," << #z << "=" << z << endl
#define dbv(v) cerr << #v << "="; for (auto _x : v) cerr << _x << ", "; cerr << endl
#define dba(a, n) cerr << #a << "="; for (int _i = 0; _i < (n); ++_i) cerr << a[_i] << ", "; cerr << endl
typedef long long ll;
typedef long double ld;
template <typename T>
struct Dinic {
	// vertices are 0..n-1
	static const T eps = 1e-9;
	int n, src, sink;
	struct Edge {
		int from, to;
		T f, cap;
	};
	vector<int> dist, Q, work;
	vector<Edge> edges;
	vector<vector<int>> G;
	Dinic(int _n) : n(_n) {
		G.resize(n);
		dist.resize(n);
		Q.resize(n);
		work.resize(n);
	}
	// Returns edge id added (rev edge is id ^ 1)
	int addEdge(int s, int t, T forwardCap, T backwardCap = 0) {
		int id = edges.size();
		G[s].push_back(id);
		edges.push_back({s, t, 0, forwardCap});
		G[t].push_back(id + 1);
		edges.push_back({t, s, 0, backwardCap});
		return id;
	}
	bool dinicBfs() {
		fill(dist.begin(), dist.begin() + n, -1);
		dist[src] = 0;
		int qt = 0;
		Q[qt++] = src;
		for (int qh = 0; qh < qt; ++qh) {
			int u = Q[qh];
			for (int eid : G[u]) {
				Edge& e = edges[eid];
				int v = e.to;
				if (dist[v] < 0 && e.cap - e.f > eps) {
					dist[v] = dist[u] + 1;
					Q[qt++] = v;
				}
			}
		}
		return dist[sink] >= 0;
	}
	T dinicDfs(int u, T f) {
		if (u == sink) return f;
		// Edges 0..work[u] - 1 have been saturated
		for (int& i = work[u]; i < G[u].size(); ++i) {
			int eid = G[u][i];
			Edge& e = edges[eid];
			if (e.cap <= e.f) continue;
			int v = e.to;
			if (dist[v] == dist[u] + 1) {
				T df = dinicDfs(v, min(f, e.cap - e.f));
				if (df > 0) {
					e.f += df;
					edges[eid ^ 1].f -= df;
					return df;
				}
			}
		}
		return 0;
	}
	T maxFlow() {
		assert(src != -1 && sink != -1);
		T result = 0;
		while (dinicBfs()) {
			fill(work.begin(), work.begin() + n, 0);
			for (;;) {
				T delta = dinicDfs(src, numeric_limits<T>::max());
				if (delta <= eps) break;
				result += delta;
			}
		}
		return result;
	}
	vector<bool> minCut() {
		maxFlow();
		vector<bool> ret(n);
		for (int i = 0; i < n; ++i)
			ret[i] = dist[i] >= 0;
		return ret;
	}
	// Matching, na=|A|, nb=|B|.
	int na, nb;
	vector<int> matcha, matchb;
	Dinic(int _na, int _nb) : Dinic(_na + _nb + 2) {
		na = _na;
		nb = _nb;
		src = n - 2;
		sink = n - 1;
		for (int i = 0; i < na; ++i) addEdge(src, i, 1);
		for (int i = 0; i < nb; ++i) addEdge(na + i, sink, 1);
	}
	int addMatchEdge(int s, int t) {
		return addEdge(s, t + na, 1);
	}
	int maxMatching() {
		int ret = maxFlow();
		matcha.resize(na);
		matchb.resize(nb);
		for (int i = 0; i < na; ++i) {
			for (int eid : G[i]) {
				auto& e = edges[eid];
				if (e.to != src && e.f == 1) {
					matcha[i] = e.to - na;
					matchb[e.to - na] = i;
				}
			}
		}
		return ret;
	}
};
int a[105][105], c[105][105];
int main() {
	int n, m;
	scanf("%d%d", &n, &m);
	for (int i = 0; i < n; ++i) {
		for (int j = 0; j < m; ++j) {
			scanf("%d", &a[i][j]);
			--a[i][j];
		}
	}
	for (int i = 0; i < m; ++i) {
		Dinic<int> g(n, n);
		for (int j = 0; j < n; ++j) {
			for (int k = i; k < m; ++k) {
				int t = a[j][k] / m;
				g.addMatchEdge(j, t);
			}
		}
		int match = g.maxMatching();
		assert(match == n);
		for (int j = 0; j < n; ++j) {
			for (int k = i; k < m; ++k) {
				if (g.matcha[j] == a[j][k] / m) {
					swap(a[j][i], a[j][k]);
					break;
				}
			}
		}
	}
	for (int i = 0; i < m; ++i) {
		vector<int> tmp(n);
		for (int j = 0; j < n; ++j) {
			tmp[j] = a[j][i];
		}
		sort(tmp.begin(), tmp.end());
		for (int j = 0; j < n; ++j) c[j][i] = tmp[j];
	}
	for (int i = 0; i < n; ++i) {
		for (int j = 0; j < m; ++j) {
			printf("%d ", a[i][j] + 1);
		}
		printf("\n");
	}
	for (int i = 0; i < n; ++i) {
		for (int j = 0; j < m; ++j) {
			printf("%d ", c[i][j] + 1);
		}
		printf("\n");
	}
}


Measured memory_bytes: 1168