#include<stdio.h>
#include<iostream>
#include<vector>
#include<algorithm>
#include<string>
#include<string.h>

#ifdef LOCAL
#define eprintf(...) fprintf(stderr, __VA_ARGS__)
#else
#define NDEBUG
#define eprintf(...) do {} while (0)
#endif
#include<cassert>

using namespace std;

typedef long long LL;
typedef vector<int> VI;

#define REP(i,n) for(int i=0, i##_len=(n); i<i##_len; ++i)
#define EACH(i,c) for(__typeof((c).begin()) i=(c).begin(),i##_end=(c).end();i!=i##_end;++i)

template<class T> inline void amin(T &x, const T &y) { if (y<x) x=y; }
template<class T> inline void amax(T &x, const T &y) { if (x<y) x=y; }
template<class Iter> void rprintf(const char *fmt, Iter begin, Iter end) {
    for (bool sp=0; begin!=end; ++begin) { if (sp) putchar(' '); else sp = true; printf(fmt, *begin); }
    putchar('\n');
}
struct Matching2 { // for bipartite graph
    static const int INF = 1<<29;
    const VI* G;
    VI matchM, matchW, dist;
    int ans;
    int SNK;

    bool dfs(int v) {
	if (v == SNK) return true;
	EACH (e, G[v]) if (dist[matchW[*e]] == dist[v]+1 && dfs(matchW[*e])) {
	    matchM[v] = *e;
	    matchW[*e] = v;
	    return true;
	}
	dist[v] = INF;
	return false;
    }

    Matching2(const VI G_[], int sizeM, int sizeW): G(G_), matchM(sizeM, -1), matchW(sizeW, sizeM), dist(sizeM+1), ans(0), SNK(sizeM) {
	VI qu; qu.reserve(sizeM+1);
	while (1) {
	    dist[SNK] = INF;
	    REP (i, sizeM) {
		if (matchM[i] == -1) { dist[i] = 0; qu.push_back(i); }
		else dist[i] = INF;
	    }
	    for (int i=0; i<(int)qu.size(); i++) {
		int v = qu[i];
		if (dist[v] < dist[SNK]) {
		    EACH (e, G[v]) if (dist[matchW[*e]] == INF) {
			dist[matchW[*e]] = dist[v] + 1;
			qu.push_back(matchW[*e]);
		    }
		}
	    }
	    if (dist[SNK] == INF) break;
	    qu.clear();
	    REP (i, sizeM) if (matchM[i] == -1 && dfs(i)) ans++;
	}
	REP (i, sizeW) if (matchW[i] == SNK) matchW[i] = -1;
    }

    // NOTE: vertex cover is not unique;
    // In residual graph, VC := (M \cap unreachable from S) \cup (W \cap reachable from S);
    void vertext_cover(VI &ansM, VI &ansW) {
	VI st;
	vector<bool> useM(matchM.size());
	vector<bool> useW(matchW.size());
	REP (i, matchM.size()) if (matchM[i] == -1) {
	    useM[i] = true;
	    st.push_back(i);
	}
	while (!st.empty()) {
	    int v = st.back(); st.pop_back();
	    EACH (e, G[v]) if (*e != matchM[v] && !useW[*e]) {
		useW[*e] = true;
		if (!useM[matchW[*e]]) {
		    useM[matchW[*e]] = true;
		    st.push_back(matchW[*e]);
		}
	    }
	}
	REP (i, matchM.size()) if (!useM[i]) ansM.push_back(i);
	REP (i, matchW.size()) if (useW[i]) ansW.push_back(i);
    }
};

int N, M;
int A[111][111];
int B[111];
VI G[10011];

void MAIN() {
    scanf("%d%d", &N, &M);
    REP (i, N) REP (j, M) scanf("%d", &A[i][j]);

    for (int r=M; r>0; r--) {
	REP (i, N) G[i].clear();
	REP (i, N) REP (j, r) {
	    int y = (A[i][j]-1) / M;
	    G[i].push_back(y);
	}
	Matching2 X(G, N, N);

	REP (i, N) {
	    REP (j, r) {
		int y = (A[i][j]-1) / M;
		if (X.matchM[i] == y) {
		    swap(A[i][j], A[i][r-1]);
		    break;
		}
	    }
	}
    }

    REP (i, N) rprintf("%d", A[i], A[i]+M);

    REP (j, M) {
	REP (i, N) B[i] = A[i][j];
	sort(B, B+N);
	REP (i, N) A[i][j] = B[i];
    }
    REP (i, N) rprintf("%d", A[i], A[i]+M);
}

int main() {
    int TC = 1;
//    scanf("%d", &TC);
    REP (tc, TC) MAIN();
    return 0;
}



Measured memory_bytes: 640