#include <bits/stdc++.h>

using namespace std;

using int64 = long long;

template<typename T>
vector<vector<T>> Make2DVector(int d1, int d2, T default_value) {
  return vector<vector<T>>(d1, vector<T>(d2, default_value));
}

struct FlowEdge {
  const int from, to;
  const int64 cap;  // Capacity
  const int label;
  FlowEdge(int from, int to, int64 cap, int label) :
      from(from), to(to), cap(cap), label(label) {}
};

tuple<int64, vector<int64>>
MaxFlow(int n, const vector<FlowEdge>& edges, int s, int t) {
  int m = edges.size();
  
  vector<vector<tuple<FlowEdge, int>>> graph(n);
  vector<int64> res_caps(2 * m);  // Edge ID to residual capacity
  vector<int> to_reverse(2 * m, -1);  // Edge ID to the reverse edge ID
  for (int i = 0; i < m; i++) {
    const auto& edge = edges[i];
    graph[edge.from].push_back(make_tuple(edge, i));
    graph[edge.to].push_back(
        make_tuple(FlowEdge(edge.to, edge.from, 0, -1), m + i));
    res_caps[i] = edge.cap;
    to_reverse[i] = m + i;
    to_reverse[m + i] = i;
  }

  int64 total = 0;
  while (true) {
    queue<int> q;
    vector<int> prevs(n, -1);
    vector<int> used_edges(n, -1);
    q.push(s);
    while (!q.empty()) {
      int v = q.front();
      q.pop();
      for (const auto& edge_tuple : graph[v]) {
        FlowEdge edge = get<0>(edge_tuple);
        int edge_id = get<1>(edge_tuple);
        if (res_caps[edge_id] == 0 || prevs[edge.to] >= 0) continue;
        prevs[edge.to] = v;
        used_edges[edge.to] = edge_id;
        q.push(edge.to);
      }
    }

    if (prevs[t] == -1) return make_tuple(total, res_caps);

    int cur = t;
    vector<int> path;
    while (cur != s) {
      path.push_back(used_edges[cur]);
      cur = prevs[cur];
    }

    int64 inc = INT64_MAX;
    for (int edge_id : path) {
      inc = min(inc, res_caps[edge_id]);
    }

    total += inc;

    for (int edge_id : path) {
      res_caps[edge_id] -= inc;
      res_caps[to_reverse[edge_id]] += inc;
    }
  }
}

int main() {
  ios::sync_with_stdio(false);
  cin.tie(0);

  int n, m;
  cin >> n >> m;
  auto matrix = Make2DVector<int>(n, m, 0);
  for (int r = 0; r < n; r++) {
    for (int c = 0; c < m; c++) {
      cin >> matrix[r][c];
      matrix[r][c]--;
    }
  }

  vector<int> used(n * m);
  auto ans = Make2DVector(n, m, -1);
  for (int k = 0; k < m; k++) {
    vector<FlowEdge> edges;
    for (int r = 0; r < n; r++) {
      for (int c = 0; c < m; c++) {
        if (used[matrix[r][c]]) continue;
        edges.push_back(FlowEdge(r, n + matrix[r][c] / m, 1, matrix[r][c]));
      }
    }
    int s = 2 * n;
    int t = 2 * n + 1;
    for (int r = 0; r < n; r++) {
      edges.push_back(FlowEdge(s, r, 1, -1));
      edges.push_back(FlowEdge(n + r, t, 1, -1));
    }

    int64 flow;
    vector<int64> res_caps;
    tie(flow, res_caps) = MaxFlow(2 * n + 2, edges, s, t);
    for (int i = 0; i < edges.size(); i++) {
      const auto& edge = edges[i];
      if (edge.label >= 0 && res_caps[i] == 0) {
        ans[edge.from][k] = edge.label;
        used[edge.label] = 1;
      }
    }
  }

  for (int r = 0; r < n; r++) {
    for (int c = 0; c < m; c++) {
      cout << ans[r][c] + 1 << " ";
    }
    cout << endl;
  }

  auto ans2 = Make2DVector(n, m, -1);
  for (int c = 0; c < m; c++) {
    vector<int> col;
    for (int r = 0; r < n; r++) {
      col.push_back(ans[r][c]);
    }
    sort(col.begin(), col.end());
    for (int r = 0; r < n; r++) {
      ans2[r][c] = col[r];
    }
  }

  for (int r = 0; r < n; r++) {
    for (int c = 0; c < m; c++) {
      cout << ans2[r][c] + 1 << " ";
    }
    cout << endl;
  }
}

Measured memory_bytes: 1948