#include <iostream>
#include <vector>
using namespace std;
using ll = long long;
const ll MOD = 1e9 + 7;

// Dinic's algorithm for max flow
// Source must be node 0, sink must be node n-1
// All edges are directed
// O(V^2 E) in general
// O(min(V^{2/3}, sqrt{E}) E) in graphs with unit capacities
// O(sqrt{V} E) in unit networks (e.g. bipartite matching)
class Dinic {
	private:
		constexpr static ll INF = 8*(ll)1e18;
		struct Edge {
			const int s, t;
			const ll c; // capacity
			ll f; // flow

			Edge(int src, int tar, ll cap = INF, bool dir = 1)
				: s(src), t(tar), c(dir ? cap : 2*cap), f(dir ? 0 : cap) {}

			int getOth(int i) { return i == s ? t : s; }
			ll getCap(int i) { return i == s ? c - f : f; }
			void push(int i, ll am) { f += (i == s ? am : -am); }
		};

		const int source, sink, n;
		vector<Edge> edges;
		vector<vector<int>> conns;
		vector<int> dist;
		vector<bool> done;
		
		bool calcDists() {
			for (int i = 0; i < n; ++i) dist[i] = n;
			dist[sink] = 0;
			vector<int> que = {sink};
			for (int j = 0; j < que.size(); ++j) {
				int i = que[j];
				for (auto ei : conns[i]) {
					int t = edges[ei].getOth(i);
					if (edges[ei].getCap(t) == 0) continue;
					if (dist[t] == n) {
						dist[t] = dist[i] + 1;
						que.push_back(t);
					}
				}
			}
			return dist[source] < n;
		}
		ll dfsFlow(int i, ll cap = INF) {
			if (i == sink) return cap;
			ll res = 0;
			for (auto ei : conns[i]) {
				int t = edges[ei].getOth(i);
				if (done[t] || dist[t] != dist[i] - 1) continue;

				ll subcap = min(cap-res, edges[ei].getCap(i));
				if (subcap == 0) {
					if (cap == res) return res;
				} else {
					ll add = dfsFlow(t, subcap);
					res += add;
					edges[ei].push(i, add);
				}
			}
			if (res < cap) done[i] = true;
			return res;
		}
	public:
		Dinic(int nn, int s, int t)
			: n(nn), conns(nn), dist(nn), done(nn), source(s), sink(t) {}

		void addEdge(int a, int b, ll c = INF, bool dir = 1) {
			edges.emplace_back(a, b, c, dir);
			conns[a].push_back(edges.size() - 1);
			conns[b].push_back(edges.size() - 1);
		}
		ll pushFlow() {
			ll res = 0;
			while(calcDists()) {
				for (int i = 0; i < n; ++i) done[i] = false;
				res += dfsFlow(source);
			}
			return res;
		}
		ll getFlow(int ei) const { return edges[ei].f; }
};

const int N = 100;
int vals[N][N];
int res[N][N];

bool bipMatch(int x, int h, int w) {
	int n = 2*h + 2;
	int source = n-2;
	int sink = n-1;

	Dinic dinic(n, source, sink);
	for (int y = 0; y < h; ++y) {
		for (int xx = x; xx < w; ++xx) {
			int v = (vals[y][xx] - 1) / w;
			dinic.addEdge(y, v + h, 1);
		}
	}
	for (int y = 0; y < h; ++y) {
		dinic.addEdge(source, y, 1);
		dinic.addEdge(y+h, sink, 1);
	}

	ll flow = dinic.pushFlow();
	if (flow < h) return false;

	for (int y = 0; y < h; ++y) {
		for (int xx = x; xx < w; ++xx) {
			int ei = y*(w-x) + (xx-x);
			if (dinic.getFlow(ei)) {
				swap(vals[y][x], vals[y][xx]);
				break;
			}
		}
	}
	return true;
}

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

	int h, w;
	cin >> h >> w;
	for (int y = 0; y < h; ++y) {
		for (int x = 0; x < w; ++x) {
			cin >> vals[y][x];
		}
	}

	bool fail = false;
	for (int x = 0; x < w; ++x) fail |= !bipMatch(x, h, w);
	if (fail) {
		cout << "QAQ\n";
	} else {
		for (int y = 0; y < h; ++y) {
			for (int x = 0; x < w; ++x) {
				cout << vals[y][x] << ' ';
			}
			cout << '\n';
		}
		for (int y = 0; y < h; ++y) {
			for (int x = 0; x < w; ++x) {
				int v = (vals[y][x] - 1) / w;
				res[v][x] = vals[y][x];
			}
		}
		for (int y = 0; y < h; ++y) {
			for (int x = 0; x < w; ++x) {
				cout << res[y][x] << ' ';
			}
			cout << '\n';
		}
	}

}


Measured memory_bytes: 988