#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
// #define int long long

#define SZ(x) ((int)(x).size())
#define ALL(x) (x).begin(),(x).end()

#define FOR(i,a,b) for(int i=(int)(a);i<(int)(b);i++)
#define REP(i,x) for(int i=0;i<(int)(x);i++)
#define REPS(i,x) for(int i=1;i<=(int)(x);i++)
#define RREP(i,x) for(int i=((int)(x)-1);i>=0;i--)
#define RREPS(i,x) for(int i=((int)(x));i>0;i--)

typedef pair<int, int> pint;

#define mp make_pair
#define mt make_tuple
#define pb push_back
#define pf push_front

#define MOD (1000 * 1000 * 1000 + 7)

#include <bits/stdc++.h>
using namespace std;

typedef int FLOW;
const FLOW INF = 10000000;

struct UnblockedPath {
    bool found = false;
    vector<int> preNodes;
    FLOW flow = 0;
};

class Graph {
public:
    int N;
    vector< vector<FLOW> > edges;
    vector< vector<bool> > added;
    vector< vector<int> > outEdges;

    Graph(int N) {
        this->N = N;

        edges = vector< vector<FLOW> >(N, vector<FLOW>(N, 0));
        added = vector< vector<bool> >(N, vector<bool>(N, false));
        outEdges = vector< vector<int> >(N, vector<int>());
    }

    void addEdge(int s, int t, FLOW w) {
        if (added[s][t] == false && w > 0) {
            outEdges[s].push_back(t);
        }
        edges[s][t] = w;

        if (w > 0) {
            added[s][t] = true;
        }
    }

    int getNodeNum() { return N; }

    vector<int> getOutEdges(int node) {
        return outEdges[node];
    }

    FLOW getEdge(int s, int t) {
        return edges[s][t];
    }
};

class MaxFlow {
public:
    int sink, source;
    FLOW maxFlow = 0;
    vector<UnblockedPath> paths;

    MaxFlow(int s, int t) {
        source = s;
        sink = t;
    }

    static UnblockedPath findUnblockedPath(Graph &g, int source, int sink) {
        UnblockedPath ubp{};
        ubp.preNodes = vector<int>(g.getNodeNum());
        ubp.preNodes[source] = -1;

        vector<bool> visited = vector<bool>(g.getNodeNum());

        queue<int> q;
        q.push(source);

        while (!q.empty()) {
            int currentNode = q.front();
            q.pop();
            visited[currentNode] = true;

            if (currentNode == sink) {
                ubp.found = true;
                break;
            }

            for (int nextNode: g.getOutEdges(currentNode)) {
                if (!visited[nextNode] && g.getEdge(currentNode, nextNode) > 0) {
                    ubp.preNodes[nextNode] = currentNode;
                    q.push(nextNode);
                }
            }
        }

        return ubp;
    }

    static MaxFlow FordFulkerson(Graph &g, int source, int sink) {
        MaxFlow mf(source, sink);
        FLOW increment = INF;

        while (true) {
            UnblockedPath ubp = findUnblockedPath(g, source, sink);
            if (!ubp.found) {
                break;
            }

            int end = ubp.preNodes[source];
            int temp = sink;

            while (ubp.preNodes[temp] != end) {
                increment = min(increment, g.getEdge(ubp.preNodes[temp], temp));
                temp = ubp.preNodes[temp];
            }

            ubp.flow = increment;
            mf.maxFlow += increment;
            mf.paths.push_back(ubp);

            temp = sink;
            while (ubp.preNodes[temp] != end) {
                g.addEdge(ubp.preNodes[temp], temp, g.getEdge(ubp.preNodes[temp], temp) - increment);
                g.addEdge(temp, ubp.preNodes[temp], g.getEdge(temp, ubp.preNodes[temp]) + increment);
                temp = ubp.preNodes[temp];
            }
        }

        return mf;
    }

    void analyse() {
        cout << "source  : " << source << endl;
        cout << "sink    : " << sink << endl;
        cout << "maxFlow : " << maxFlow << endl;

        for (UnblockedPath ubp : paths) {
            int temp = sink;
            int end = ubp.preNodes[source];

            cout << ubp.flow << "\t: ";
            while (ubp.preNodes[temp] != end) {
                cout << temp << " => ";
                temp = ubp.preNodes[temp];
            }
            cout << source << endl;
        }
    }
};

signed main() {
    int N, M;
    cin >> N >> M;

    vector< vector<int> > A(N, vector<int>(M, 0));
    REP (i, N) {
        REP (j, M) {
            cin >> A[i][j];
        }
    }

    int start = 2 * N;
    int goal  = 2 * N + 1;
    vector <vector <bool> > check(N, vector<bool>(M, false));
    vector <vector <int> > B(M, vector<int>(N, 0));

    REP (J, M) {
        Graph g(2*N+2);

        vector <vector <int> > original(2*N+2, vector<int>(2*N+2, 0));
        vector <vector <int> > sett(2*N+2, vector<int>(2*N+2, 0));
        REP (i, N) {
            REP (j, M) {
                if (check[i][j]) continue;

                int r = (A[i][j] - 1) / M;
                g.addEdge(i, r+N, 1);
                original[i][r+N] = 1;
                sett[i][r+N] = j;
            }
        }

        REP (i, N) {
            g.addEdge(start, i, 1);
            g.addEdge(i + N, goal, 1);
        }

        MaxFlow mf = MaxFlow::FordFulkerson(g, start, goal);
        // mf.analyse();

        REP (i, N) {
            REP (_j, N) {
                int j = _j + N;

                if (original[i][j] - g.edges[i][j] == 1) {
                    int k = sett[i][j];
                    check[i][k] = true;
                    B[J][i] = A[i][k];

                    break;
                }
            }
        }
    }

    REP (i, N) {
        REP (j, M) {
            if (j != 0) cout << " ";
            cout << B[j][i];
        }
        cout << endl;
    }

    REP (j, M) {
        sort(ALL(B[j]));
    }

    REP (i, N) {
        REP (j, M) {
            if (j != 0) cout << " ";
            cout << B[j][i];
        }
        cout << endl;
    }

    return 0;
}

Measured memory_bytes: 1060