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

#define pb push_back
#define mp make_pair
typedef long long ll;
typedef pair<int, int> pii;
typedef vector<int> vi;
typedef complex<double> point;
#define xx real()
#define yy imag()

#define REP(i, a, b) for(int i = (a); i < (int)(b); i++)
#define REPN(i, a, b) for(int i = (a); i <= (int)(b); i++)
#define FA(it, x) for(__typeof((x).begin()) it = (x).begin(); it != (x).end(); it++)
#define SZ(x) (int)(x).size()
#define BE(x) (x).begin(), (x).end()
#define SORT(x) sort(BE(x))
#define _1 first
#define _2 second

#define x1 gray_cat_x1
#define y1 gray_cat_y1

template<class T> T gcd(T a, T b) { return b ? gcd(b, a % b) : a; }

mt19937 rng(chrono::steady_clock::now().time_since_epoch().count());

#define file "I1"

const double EPS = 1e-9;
const double PI = acos(-1.);
const int INF = 1e9 + 10;
const ll MOD = 1e9 + 7;

const int MAXN = 1e3 + 5;

struct graph {
	// Number of vertices for two parts
	int n;
	
	// graph (1 -> 2)
	int g[MAXN][MAXN];
	
	// Col for Kuhn series (1st part)
	int col[MAXN];
	
	// Current color for Kuhn series
	int cur_col;
	
	// Nxt for Kuhn (2nd part)
	int nxt[MAXN];
	
	// Final matching
	vector<pii> matching;	
	
	// Try_kuhn
	int try_kuhn(int s){
		if (col[s] == cur_col){
			return 0;
		}
		col[s] = cur_col;
		REP(i, 0, n){
			if (g[s][i] && (nxt[i] == -1 || try_kuhn(nxt[i]))){
				nxt[i] = s;
				return 1;
			}
		}
		return 0;
	}
	
	// Set random matching for speeding up Kuhn
	void set_random_matching(){
		REP(i, 0, n){
			if (col[i] == -1){
				REP(j, 0, n){
					if (g[i][j] && nxt[j] == -1){
						col[i] = 1;
						nxt[j] = i;
						break;
					}
				}
			}
		}
	}
	
	// Find matching
	void get_matching(){
		// Init
		REP(i, 0, n){
			col[i] = -1;
			nxt[i] = -1;
		}
		matching.clear();
		
		// Random matching
		cur_col = 1;
		set_random_matching();
						
		// Go Kuhn
		REP(i, 0, n){
			if (col[i] == -1){
				cur_col++;
				try_kuhn(i);
			}
		}
		
		// Restore matching
		REP(i, 0, n){
			if (nxt[i] != -1){
				matching.pb(mp(nxt[i], i));
			}
		}
	}	
} gg;

int v[MAXN][MAXN], v1[MAXN][MAXN];
int ans[MAXN][MAXN], ans1[MAXN][MAXN], ans_tmp[MAXN];
int used[MAXN][MAXN];

void solve(){
	int n, m;
	scanf("%d%d", &n, &m);
	REP(i, 0, n) {
		REP(j, 0, m) {
			scanf("%d", &v[i][j]);
			v1[i][j] = (v[i][j] - 1) / m;
		}
	}
	gg.n = n;
	REP(i, 0, n) {
		REP(j, 0, m) {
			gg.g[i][v1[i][j]]++;
		}
	}
	
	/*REP(i, 0, n) {
		REP(j, 0, n) {
			printf("%d ", gg.g[i][j]);
		}
		putchar('\n');
	}*/
	
	REP(k, 0, m) {
		gg.get_matching();
		REP(i, 0, SZ(gg.matching)) {
			int ind_r = gg.matching[i]._1, ind_v = gg.matching[i]._2;
			//printf("%d %d\n", ind_r, ind_v);
			gg.g[ind_r][ind_v]--;
			REP(j, 0, m) {
				if (v1[ind_r][j] == ind_v && !used[ind_r][j]) {
					used[ind_r][j] = 1;
					ans[ind_r][k] = v[ind_r][j];
					break;
				}
			}
		}
		//putchar('\n');
	}
	
	REP(j, 0, m) {
		REP(i, 0, n) {
			ans_tmp[i] = ans[i][j];
		}
		sort(ans_tmp, ans_tmp + n);
		REP(i, 0, n) {
			ans1[i][j] = ans_tmp[i];
		}
	}
	
	REP(i, 0, n) {
		REP(j, 0, m) {
			printf("%d ", ans[i][j]);
		}
		putchar('\n');
	}
	
	REP(i, 0, n) {
		REP(j, 0, m) {
			printf("%d ", ans1[i][j]);
		}
		putchar('\n');
	}
}   

int main(){

    //freopen(file".in", "r", stdin); freopen(file".out", "w", stdout);
    int t = 1;
    //cin >> t;
    while(t--){
        solve();    
    }
}


Measured memory_bytes: 15104