#include <bits/stdc++.h>
#define loop(n) for (int ngtkana_is_geneous = 0; ngtkana_is_geneous < int(n); ngtkana_is_geneous++)
#define rep(i, begin, end) for(int i = begin; i < end; i++)

#define LOCAL
using std::to_string;
auto to_string(std::string s) -> std::string {
  return '"' + s + '"';
}
auto to_string(char c) -> std::string {
  return "'" + std::string{c} + "'";
}
auto to_string(const char* s) -> std::string {
  return to_string((std::string) s);
}
auto to_string(bool b) -> std::string {
  return (b ? "true" : "false");
}
template <typename T, typename U>
auto to_string(std::pair<T, U> p) -> std::string {
  return "(" + to_string(p.first) + ", " + to_string(p.second) + ")";
}
template <size_t N>
auto to_string(std::bitset<N> bs) -> std::string {
  std::string res{};
  for (size_t i = 0; i < N; i++)
    res.insert(res.begin(), bs.test(i) ? '1' : '0');
  return res;
}
template <typename T>
auto to_string(T v) -> std::string {
  bool flg = false;
  std::string res = "{";
  for (auto const&x : v) {
    if (flg) res += ", ";
    else flg = true;
    res += to_string(x);
  }
  res += "}";
  return res;
}
void debug_out() { std::cerr << std::endl; }
template <typename Head, typename... Tail>
void debug_out(Head H, Tail... T) {
  std::cerr << " " << to_string(H);
  debug_out(T...);
}
#ifdef LOCAL
#define debug(...) std::cerr << "[" << #__VA_ARGS__ << "]:", debug_out(__VA_ARGS__)
#else
#define debug(...) 42
#endif

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

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

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

    bool bfs()
    {
      std::fill(level.begin(), level.end(), -1);
      std::queue<int> que;
      for (int i = 0; i < L; i++)
      {
        if (match_list.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_list.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_list.at(nxt);
        if (w == -1 || dfs(w))
        {
          match_list.at(nxt) = crr;
          match_list.at(crr) = nxt;
          level.at(crr) = -1;
          return true;
        }
      }
      level.at(crr) = -1;
      return false;
    }

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

    auto match() const {return match_list;}
};

template <typename T>
auto make_vector(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_higher_vector(size_t sz, U u) {
  return make_vector(sz, T(u));
}
template <size_t N, typename T, std::enable_if_t<
  N == 1, std::nullptr_t> = nullptr>
auto make_higher_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_higher_vector(size_t a, Args... args) {
  return make_vector(a, make_higher_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...);
}

int main()
{
  std::cin.tie(0); std::cin.sync_with_stdio(false);
  int n, m; std::cin >> n >> m;
  auto a = make_higher_vector<2, int>(n, m);
  for (auto& x : a) for (auto& y : x)
  {
    std::cin >> y;
    y--;
  }
  auto move = make_higher_vector<3, int>(n, n, 0);
  rep(i, 0, n) rep(j, 0, m)
  {
    auto crr  = at(a, i, j);
    auto from = i;
    auto to   = crr / m;
    at(move, from, to).emplace_back(crr);
  }
  auto b = make_higher_vector<2, int>(n, m);
  auto c = make_higher_vector<2, int>(n, m);
  rep(col, 0, m)
  {
    auto bip = bipartite_matching(n, n);
    rep(from, 0, n) rep(to, 0, n) loop(at(move, from, to).size())
    {
      bip.insert_edge(from, to);
    }
    bip.build();
    auto match = bip.match();
    for (int i = 0; i < n; i++)
    {
      auto  from   = i;
      auto  to     = match.at(i) - n;
      auto& source = at(move, from, to);
      assert(to != -1);
      assert(!source.empty());
      at(b, from, col) = at(c, to, col) = source.back(); source.pop_back();
    }
  }
  for (int i = 0; i < n; i++)
  {
    for (int j = 0; j < m; j++)
    {
      std::cout << (j > 0 ? " " : "") << at(b, i, j) + 1;
    }
    std::cout << std::endl;
  }
  for (int i = 0; i < n; i++)
  {
    for (int j = 0; j < m; j++)
    {
      std::cout << (j > 0 ? " " : "") << at(c, i, j) + 1;
    }
    std::cout << std::endl;
  }
  return 0;
}

Measured memory_bytes: 1152