#define STOPIT
#include <bits/stdc++.h>
#define loop(n) for (int ngtkana_is_genius = 0; ngtkana_is_genius < int(n); ngtkana_is_genius++)
#define rep(i, begin, end) for(int i = int(begin); i < int(end); i++)
#define all(v) v.begin(), v.end()
#define rand(l, r) std::uniform_int_distribution<>(l, r)(mt)
#define lint long long
auto cmn = [](auto& a, auto b){if (a > b) {a = b; return true;} return false;};
auto cmx = [](auto& a, auto b){if (a < b) {a = b; return true;} return false;};
void debug_impl() { std::cerr << std::endl; }
template <typename Head, typename... Tail>
void debug_impl(Head head, Tail... tail){
  std::cerr << " " << head;
  debug_impl(tail...);
}
#ifndef STOPIT
#define debug(...)\
  std::cerr << std::boolalpha << "[" << #__VA_ARGS__ << "]:";\
  debug_impl(__VA_ARGS__);\
  std::cerr << std::noboolalpha;
#else
#define debug 0;
#endif

class bipartite_matching
{
    int L, R;
    std::vector<std::vector<int>> graph;
    std::vector<int> match, level;

    bool bfs()
    {
      std::fill(level.begin(), level.end(), -1);
      std::queue<int> que;
      for (int i = 0; i < L; i++)
      {
        if (match.at(i) < 0)
        {
          level.at(i) = 0;
          que.emplace(i);
        }
      }
      bool ret = false;
      while (!que.empty())
      {
        auto crr = que.front(); que.pop();
        for (auto nxt : graph.at(crr))
        {
          if (level.at(nxt) != -1) continue;
          level.at(nxt) = level.at(crr) + 1;
          auto w = match.at(nxt);
          if (w == -1)
          {
            ret = true;
          }
          else if (level.at(w) == -1)
          {
            level.at(w) = level.at(crr) + 1;
            que.emplace(w);
          }
        }
      }
      return ret;
    }

    bool dfs(int crr)
    {
      for (auto nxt : graph.at(crr))
      {
        assert(level.at(nxt) <= level.at(crr) + 1);
        if (level.at(nxt) < level.at(crr) + 1) continue;
        level.at(nxt) = -1;
        auto w = match.at(nxt);
        if (w == -1 || dfs(w))
        {
          match.at(nxt) = crr;
          match.at(crr) = nxt;
          level.at(crr) = -1;
          return true;
        }
      }
      level.at(crr) = -1;
      return false;
    }

  public:
    bipartite_matching()=default;
    bipartite_matching(int L, int R):
      L(L), R(R), graph(L + R), match(L + R, -1), level(L + R)
      {}

    void insert(int u, int v)
    {
      v += L;
      graph.at(u).emplace_back(v);
      graph.at(v).emplace_back(u);
    }


    int build ()
    {
      auto ret = 0;
      while (bfs())
      {
        for (int i = 0; i < L; i++)
        {
          if (match.at(i) == -1 && dfs(i))
          {
            ret++;
          }
        }
      }
      return ret;
    }

    auto collect() const {return match;}

    auto count() const
    {
      auto k = L + R - std::count(match.begin(), match.end(), -1);
      assert(k % 2 == 0);
      return k / 2;
    }
};

template <typename T>
auto make_vector_impl(size_t sz, T t) {return std::vector<T>(sz, t);}

template <size_t N, typename T, typename U, std::enable_if_t<N == 1, std::nullptr_t> = nullptr>
auto make_vector(size_t sz, U u) {return make_vector_impl(sz, T(u));}

template <size_t N, typename T, std::enable_if_t<N == 1, std::nullptr_t> = nullptr>
auto make_vector(size_t sz) {return std::vector<T>(sz);}

template <size_t N, typename T, typename... Args, std::enable_if_t<N != 1, std::nullptr_t> = nullptr>
auto make_vector(size_t a, Args... args) {return make_vector_impl(a, make_vector<N - 1, T>(args...));}

template <typename T, typename Size_t>
auto& at(T& t, Size_t i) {return t.at(i);}

template <typename T, typename Size_t, typename... Args>
auto& at(T& t, Size_t i, Args... args) {return at(t.at(i), args...);}

template < typename Container,
  typename Value = typename Container::value_type,
  std::enable_if_t<!std::is_same< Container, std::string >::value, std::nullptr_t> = nullptr
>
std::istream& operator>> (std::istream& is, Container& v) {
  for (auto & x : v) is >> x;
  return is;
}

template < typename Container,
  typename Value = typename Container::value_type,
  std::enable_if_t<!std::is_same< Container, std::string >::value, std::nullptr_t> = nullptr
>
std::ostream& operator<< (std::ostream& os, Container const& v) {
  os << "{";
  for (auto it = v.begin(); it != v.end(); it++)
    {os << (it != v.begin() ? "," : "") << *it;}
  return os << "}";
}

int main() {
  std::cin.tie(0); std::cin.sync_with_stdio(false);
  int n, m; std::cin >> n >> m;
  auto N = n * m;
  auto a = make_vector< 2, int >(n, m);
  std::cin >> a;
  for (auto & v : a) for (auto & x : v) x--;
  debug(a);
  auto edges = make_vector< 3, int >(n, n, 0);
  rep(i, 0, n) {
    for (auto x : a.at(i)) {
      auto j = x / m;
      at(edges, i, j).emplace_back(x);
    }
  }
  debug(edges);
  auto col = std::vector< int >(N, -1);
  rep(c, 0, m) {
    auto bpm = bipartite_matching(n, n);
    rep(i, 0, n) rep(j, 0, n) {
      for (auto x : at(edges, i, j))
        { bpm.insert(i, j); }
    }
    bpm.build();
    auto mate = bpm.collect();
    debug(mate);
    rep(i, 0, n) {
      auto j = mate.at(i);
      assert(j != -1);
      j -= n;
      auto & src = at(edges, i, j);
      assert(!src.empty());
      auto x = src.back();
      src.pop_back();
      col.at(x) = c;
    }
    debug(col);
  }
  auto b = make_vector< 2, int >(n, m, -1);
  auto c = make_vector< 2, int >(n, m, -1);
  rep(i, 0, n) {
    for(auto x : a.at(i)) {
      auto & tar = at(b, i, col.at(x));
      assert(tar == -1);
      tar = x;
    }
  }
  debug(b);
  rep(i, 0, n) rep(j, 0, m) {
    auto x = i * m + j;
    auto & tar = at(c, i, col.at(x));
    assert(tar == -1);
    tar = x;
  }
  debug(c);
  auto print = [&] (auto&& b) {
    rep(i, 0, n) {
      rep(j, 0, m)
        { std::cout << (j > 0 ? " " : "") << at(b, i, j) + 1; }
      std::cout << std::endl;
    }
  };
  print(b);
  print(c);

  // check
  auto arow = std::vector< int >(N, -1);
  auto brow = std::vector< int >(N, -1);
  auto crow = std::vector< int >(N, -1);
  auto drow = std::vector< int >(N, -1);
  auto acol = std::vector< int >(N, -1);
  auto bcol = std::vector< int >(N, -1);
  auto ccol = std::vector< int >(N, -1);
  auto dcol = std::vector< int >(N, -1);
  rep(i, 0, n) rep(j, 0, m) {
    auto x = at(a, i, j);
    auto y = at(b, i, j);
    auto z = at(c, i, j);
    auto w = i * m + j;
    arow.at(x) = i;
    acol.at(x) = j;
    brow.at(y) = i;
    bcol.at(y) = j;
    crow.at(z) = i;
    ccol.at(z) = j;
    drow.at(w) = i;
    dcol.at(w) = j;
  }
  debug(arow);
  debug(acol);
  debug(brow);
  debug(bcol);
  debug(crow);
  debug(ccol);
  debug(drow);
  debug(dcol);
  assert(arow == brow);
  assert(bcol == ccol);
  assert(crow == drow);
  return 0;
}


Measured memory_bytes: 1408