#include<stdio.h>
#include<vector>
#include<algorithm>
#include<queue>
using namespace std;
#define INF 1000000
typedef pair<int, int>pii;
#define SIZE 333
class maxflow
{
public:
	vector<int>pat[SIZE];
	vector<int>cap[SIZE];
	vector<int>rev[SIZE];
	bool flag[SIZE];
	int dist[SIZE];
	int now[SIZE], ind[SIZE];
	int idx[SIZE];
	int flow;
	int gd;
	void adde(int s, int t, int cp)//多重辺は消してから s->tの容量cpの辺をはる
	{
		pat[s].push_back(t);
		pat[t].push_back(s);
		cap[s].push_back(cp);
		cap[t].push_back(0);
		rev[s].push_back(pat[t].size() - 1);
		rev[t].push_back(pat[s].size() - 1);
	}
	void blockflow(int node, int len, int go, int pt)//ブロックフローを求めて流す
	{
		if (pt == len)
		{
			if (node != go)return;
			int mini = INF, rr = -1;
			for (int i = 0; i < pt; i++)if (cap[now[i]][ind[i]] < mini)mini = cap[now[i]][ind[i]], rr = i;
			for (int i = 0; i < pt; i++)cap[now[i]][ind[i]] -= mini, cap[pat[now[i]][ind[i]]][rev[now[i]][ind[i]]] += mini;
			flow += mini;//mini==INFになったら非有界
			gd = rr;
			return;
		}
		now[pt] = node;
		for (int i = idx[node]; i < pat[node].size(); i++)
		{
			if (dist[pat[node][i]] == dist[node] + 1 && cap[node][i]>0)
			{
				ind[pt] = i;
				blockflow(pat[node][i], len, go, pt + 1);
				if (gd < pt)break;
				else gd = INF;
			}
			idx[node]++;
		}
	}
	void dinic(int st, int go, int num)//dinicのアルゴリズムで最大流を求める 変数flowにmaxflowの値が入る
	{
		flow = 0;
		for (;;)
		{
			queue<pii>que;
			fill(dist, dist + num, INF);
			fill(flag, flag + num, false);
			que.push(make_pair(st, 0));
			for (;;)
			{
				if (que.empty())break;
				pii z = que.front();
				que.pop();
				if (flag[z.first])continue;
				flag[z.first] = true;
				dist[z.first] = z.second;
				for (int i = 0; i < pat[z.first].size(); i++)
				{
					if (dist[pat[z.first][i]]>z.second + 1 && cap[z.first][i] > 0)
					{
						dist[pat[z.first][i]] = z.second + 1;
						que.push(make_pair(pat[z.first][i], z.second + 1));
					}
				}
			}
			if (dist[go] == INF)return;
			gd = INF;
			fill(idx, idx + SIZE, 0);
			blockflow(st, dist[go], go, 0);
		}
	}
	vector<int>getcut(int st, int go, int num)//頂点iがmincutのst側なら1 そうでなければ0
	{
		dinic(st, go, num);
		vector<int>ret;
		for (int i = 0; i < num; i++)ret.push_back(flag[i]);
		return ret;
	}
};
int m[222][222];
int col[222][222];
int ans[222][222];
int main()
{
	int mx, my;
	scanf("%d%d", &mx, &my);
	for (int i = 0; i < mx; i++)for (int j = 0; j < my; j++)scanf("%d", &m[i][j]);
	for (int i = 0; i < mx; i++)for (int j = 0; j < my; j++)col[i][j] = -1;
	for (int i = 0; i < my; i++)
	{
		maxflow gr;
		for (int j = 0; j < mx; j++)
		{
			for (int k = 0; k < my; k++)
			{
				if (col[j][k] == -1)
				{
					gr.adde(j, (m[j][k] - 1) / my + mx, 1);
				}
			}
		}
		for (int j = 0; j < mx; j++)gr.adde(mx + mx, j, 1);
		for (int j = 0; j < mx; j++)gr.adde(j + mx, mx + mx + 1, 1);
		gr.dinic(mx + mx, mx + mx + 1, mx + mx + 2);
		for (int j = 0; j < mx; j++)
		{
			int t = -1;
			for (int k = 0; k < gr.pat[j].size(); k++)
			{
				if (gr.pat[j][k] < mx + mx&&gr.cap[j][k] == 0)t = gr.pat[j][k] - mx;
			}
			for (int k = 0; k < my; k++)
			{
				if ((m[j][k] - 1) / my == t&&col[j][k] == -1)
				{
					col[j][k] = i;
					break;
				}
			}
		}
	}
	for (int i = 0; i < mx; i++)for (int j = 0; j < my; j++)ans[col[i][j]][i] = m[i][j];
	for (int i = 0; i < mx; i++)
	{
		for (int j = 0; j < my; j++)
		{
			printf("%d ", ans[j][i]);
		}
		printf("\n");
	}
	for (int i = 0; i < my; i++)sort(ans[i], ans[i] + mx);
	for (int i = 0; i < mx; i++)
	{
		for (int j = 0; j < my; j++)
		{
			printf("%d ", ans[j][i]);
		}
		printf("\n");
	}
}

Measured memory_bytes: 1440