/**
 * code generated by JHelper
 * More info: https://github.com/AlexeyDmitriev/JHelper
 * @author aajisaka
 */

#include<bits/stdc++.h>

using namespace std;

void debug_out() { cerr << endl; }
template <typename Head, typename... Tail>
void debug_out(Head H, Tail... T) {
  cerr << " " << to_string(H);
  debug_out(T...);
}
#ifdef LOCAL
#define debug(...) cerr << "[" << #__VA_ARGS__ << "]:", debug_out(__VA_ARGS__)
#else
#define debug(...) 42
#endif

#define SPEED ios_base::sync_with_stdio(false);cin.tie(nullptr)
#define rep(i,n) for(int i=0; i<(int)(n); i++)
#define all(v) v.begin(), v.end()
template<class T> inline bool chmax(T& a, T b) { if (a < b) { a = b; return true; } return false; }
template<class T> inline bool chmin(T& a, T b) { if (a > b) { a = b; return true; } return false; }

using ll = long long;
using ull = unsigned long long;
using P = pair<ll, ll>;

constexpr long double PI = 3.14159265358979323846264338327950288L;
mt19937_64 rng(chrono::steady_clock::now().time_since_epoch().count());

class DSortingAGrid {
public:

    struct Dinic {
        struct edge { int to; ll cost; int rev; };
        int N;
        vector<vector<edge>> graph;
        vector<int> level;
        vector<int> iter;

        void init(int n) {
          graph.resize(n+1);
          level.resize(n+1);
          iter.resize(n+1);
          N=n+1;
        }

        void add_edge(int from, int to, ll cost) {
          int r1 = graph[from].size();
          int r2 = graph[to].size();
          graph[from].push_back((edge){to, cost, r2});
          graph[to].push_back((edge){from, 0, r1});
        }

        void bfs(int s) {
          for(int i=0; i<N; i++) level[i] = -1;
          queue<int> que;
          level[s] = 0; que.push(s);
          while(!que.empty()) {
            int v = que.front(); que.pop();
            for(auto& e: graph[v]) {
              if (e.cost > 0 && level[e.to] < 0) {
                level[e.to] = level[v] + 1;
                que.push(e.to);
              }
            }
          }
        }

        ll dfs(int v, int t, ll f) {
          if (v == t) return f;
          for(int &i = iter[v]; i < graph[v].size(); i++) {
            iter[v] = i;
            edge &e = graph[v][i];
            if (e.cost > 0 && level[v] < level[e.to]) {
              ll d = dfs(e.to, t, min(f, e.cost));
              if (d > 0) {
                e.cost -= d;
                graph[e.to][e.rev].cost += d;
                return d;
              }
            }
          }
          return 0;
        }

        ll max_flow(int s, int t) {
          ll flow = 0;
          while(true) {
            bfs(s);
            if (level[t] < 0) return flow;
            for(int i=0; i<N; i++) iter[i] = 0;
            ll f;
            while((f = dfs(s, t, LLONG_MAX/4)) > 0) {
              flow += f;
            }
          }
        }
    };

    void solve(istream& cin, ostream& cout) {
      SPEED;
      int n, m; cin >> n >> m;
      vector<vector<int>> a(n, vector<int>(m));
      vector<vector<int>> b(n, vector<int>(m));
      vector<vector<int>> c(n, vector<int>(m));
      vector<bool> used(m*n);

      rep(i, n) {
        rep(j, m) {
          cin >> a[i][j];
          a[i][j]--;
        }
      }

      rep(j, m) {
        Dinic d;
        d.init(2*n+2);
        rep(i, n) {
          d.add_edge(0, i+1, 1);
          d.add_edge(i+1+n, 2*n+1, 1);
        }
        map<P, int> mp;
        rep(i, n) {
          rep(k, m) {
            if (used[a[i][k]]) continue;
            int from = i+1;
            int to = a[i][k]/m + 1 + n;
            //debug(from, to);
            d.add_edge(from, to, 1);
            mp[{from, to}] = a[i][k];
          }
        }
        int f = d.max_flow(0, 2*n+1);
        //debug(f);
        assert(f == n);
        rep(i, n) {
          for(auto e: d.graph[i+1]) {
            if (e.to == 0) continue;
            if (e.cost == 0) {
              int now = mp[{i+1, e.to}];
              b[i][j] = now;
              used[now] = true;
            }
          }
        }
      }

      rep(i, n) {
        rep(j, m) {
          cout << b[i][j]+1 << ' ';
        }
        cout << '\n';
      }

      rep(j, m) {
        vector<int> v(n);
        rep(i, n) {
          v[i] = b[i][j];
        }
        sort(all(v));
        rep(i, n) {
          c[i][j] = v[i];
        }
      }

      rep(i, n) {
        rep(j, m) {
          cout << c[i][j]+1 << ' ';
        }
        cout << '\n';
      }

    }
};

signed main() {
  DSortingAGrid solver;
  std::istream& in(std::cin);
  std::ostream& out(std::cout);
  solver.solve(in, out);
  return 0;
}

Measured memory_bytes: 1688