#include <bits/stdc++.h>
#include <ext/pb_ds/assoc_container.hpp>

using namespace std;
using namespace __gnu_pbds;

template<class T>
using ordered_set = tree<T, null_type, less<T>, rb_tree_tag, tree_order_statistics_node_update>;

random_device rd;
mt19937 rng(rd());

template<class T>
T randomize(T mod)
{
	return uniform_int_distribution<T>(0, mod - 1)(rng);
}

template<class T, class U>
void ckmin(T &a, U b)
{
    if (a > b) a = b;
}

template<class T, class U>
void ckmax(T &a, U b)
{
    if (a < b) a = b;
}

#define MP make_pair
#define PB push_back
#define LB lower_bound
#define UB upper_bound
#define fi first
#define se second
#define SZ(x) ((int) (x).size())
#define ALL(x) (x).begin(), (x).end()
#define FOR(i, a, b) for (auto i = (a); i < (b); i++)
#define FORD(i, a, b) for (auto i = (a) - 1; i >= (b); i--)

typedef long long ll;
typedef long double ld;
typedef pair<int, int> pii;
typedef pair<ll, ll> pll;
typedef vector<int> vi;
typedef vector<ll> vl;
typedef vector<pii> vpi;
typedef vector<pll> vpl;

const int MAXN = 113;

int N, M;
int grid[MAXN][MAXN];
vi edge[2 * MAXN];
int match[2 * MAXN];
bitset<2 * MAXN> seen;

bool dfs(int u)
{
	if (seen[u]) return false;
	seen[u] = true;
	for (int v : edge[u])
	{
		if (match[v] == -1 || dfs(match[v]))
		{
			match[u] = v;
			match[v] = u;
			return true;
		}
	}
	return false;
}
int matching()
{
	int res = 0;
    fill(match, match + 2 * N, -1);
	FOR(i, 0, N)
	{
		FOR(j, 0, 2 * N)
        {
            seen[j] = false;
        }
		if (dfs(i)) res++;
	}
	return res;
}

int32_t main()
{
    cout << fixed << setprecision(12);
    cerr << fixed << setprecision(4);
    ios_base::sync_with_stdio(false); cin.tie(0);
    cin >> N >> M;
    FOR(i, 0, N)
    {
        FOR(j, 0, M)
        {
            cin >> grid[i][j];
            grid[i][j]--;
        }
    }
    FOR(i, 0, M)
    {
        //cool!
        FOR(j, 0, 2 * N)
        {
            edge[j].clear();
        }
        FOR(j, 0, N)
        {
            FOR(k, i, M)
            {
                //consider the rows!
                int u = grid[j][k] / M + N;
                edge[j].PB(u);
                edge[u].PB(j);
            }
            //find a perfect matching! you're guaranteed that one exists.
        }
        assert(matching() == N);
        FOR(j, 0, N)
        {
            int x = match[j] - N;
            FOR(k, i + 1, M)
            {
                if (grid[j][k] / M == x)
                {
                    swap(grid[j][k], grid[j][i]);
                }
            }
        }
    }
    FOR(i, 0, N)
    {
        FOR(j, 0, M)
        {
            cout << grid[i][j] + 1 << " \n"[j == M - 1];
        }
    }
    FOR(i, 0, M)
    {
        FOR(j, 0, N)
        {
            FOR(k, j + 1, N)
            {
                if (grid[k][i] / M == j)
                {
                    swap(grid[j][i], grid[k][i]);
                }
            }
        }
    }
    FOR(i, 0, N)
    {
        FOR(j, 0, M)
        {
            cout << grid[i][j] + 1 << " \n"[j == M - 1];
        }
    }
    return 0;
    //bipartite graph, find a perfect matching.
    //basically, you want all columns to form permutations after the fact.
}


Measured memory_bytes: 512