#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 {
  int from, to;
  int64 cap;
  int id;
  int label = -1;
};

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

  int64 total = 0;
  while (true) {
    queue<int> q;
    vector<int> prevs(n, -1);
    vector<int> last_edges(n, -1);
    q.push(s);
    while (!q.empty()) {
      int v = q.front();
      q.pop();
      for (const auto& edge : graph[v]) {
        if (res_caps[edge.id] == 0 || prevs[edge.to] >= 0) continue;
        prevs[edge.to] = v;
        last_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(last_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, edges.size(), 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, edges.size(), -1});
      edges.push_back(FlowEdge({n + r, t, 1, edges.size(), -1}));
    }

    int64 flow;
    vector<int64> res_caps;
    tie(flow, res_caps) = MaxFlow(2 * n + 2, edges, s, t);
    for (const auto& edge : edges) {
      if (edge.label >= 0 && res_caps[edge.id] == 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: 1696