#include <limits>
#include <initializer_list>
#include <utility>
#include <bitset>
#include <tuple>
#include <type_traits>
#include <functional>
#include <string>
#include <array>
#include <deque>
#include <list>
#include <queue>
#include <stack>
#include <vector>
#include <map>
#include <set>
#include <unordered_map>
#include <unordered_set>
#include <iterator>
#include <algorithm>
#include <complex>
#include <random>
#include <numeric>
#include <iostream>
#include <iomanip>
#include <sstream>
#include <regex>
#include <cassert>
#include <cstddef>
#define endl codeforces
#define ALL(v) std::begin(v), std::end(v)
#define ALLR(v) std::rbegin(v), std::rend(v)
using ll = std::int64_t;
using ull = std::uint64_t;
using pii = std::pair<int, int>;
using tii = std::tuple<int, int, int>;
using pll = std::pair<ll, ll>;
using tll = std::tuple<ll, ll, ll>;
template <typename T> using vec = std::vector<T>;
template <typename T> using vvec = vec<vec<T>>;
template <typename T> const T& var_min(const T &t) { return t; }
template <typename T> const T& var_max(const T &t) { return t; }
template <typename T, typename... Tail> const T& var_min(const T &t, const Tail&... tail) { return std::min(t, var_min(tail...)); }
template <typename T, typename... Tail> const T& var_max(const T &t, const Tail&... tail) { return std::max(t, var_max(tail...)); }
template <typename T, typename... Tail> void chmin(T &t, const Tail&... tail) { t = var_min(t, tail...); }
template <typename T, typename... Tail> void chmax(T &t, const Tail&... tail) { t = var_max(t, tail...); }
template <typename T> const T& clamp(const T &t, const T &low, const T &high) { return std::max(low, std::min(high, t)); }
template <typename T> void chclamp(T &t, const T &low, const T &high) { return t = clamp(t, low, high); }
template <typename T> T make_v(T init) { return init; }
template <typename T, typename... Tail> auto make_v(T init, std::size_t s, Tail... tail) { auto v = std::move(make_v(init, tail...)); return vec<decltype(v)>(s, v); }
template <typename T, std::size_t Head, std::size_t ...Tail> struct multi_dem_array { using type = std::array<typename multi_dem_array<T, Tail...>::type, Head>; };
template <typename T, std::size_t Head> struct multi_dem_array<T, Head> { using type = std::array<T, Head>; };
template <typename T, std::size_t ...Args> using mdarray = typename multi_dem_array<T, Args...>::type;
namespace init__ { struct InitIO { InitIO() { std::cin.tie(nullptr); std::ios_base::sync_with_stdio(false); std::cout << std::fixed << std::setprecision(30); } } init_io; }

namespace graph {

using Node = ll;
using Weight = ll;
using Edge = std::pair<Node, Weight>;

template <bool Directed>
struct Graph : public vvec<Edge> {
    using vvec<Edge>::vvec;

    void add_edge(Node f, Node t, Weight w = 1) {
        (*this)[f].emplace_back(t, w);
        if (!Directed) (*this)[t].emplace_back(f, w);
    }

    Graph<Directed> build_inv() const {
        Graph<Directed> ret(this->size());
        for (Node i = 0; i < this->size(); i++) {
            for (const Edge &e : (*this)[i]) {
                Node j;
                Weight w;
                std::tie(j, w) = e;
                if (!Directed && j < i) continue;
                ret.add_edge(j, i, w);
            }
        }

        return ret;
    }
};

template <typename Iterator>
class dst_iterator {
    Iterator ite;

public:
    dst_iterator(Iterator ite) : ite(ite) { }

    bool operator ==(const dst_iterator<Iterator> &oth) const {
        return ite == oth.ite;
    }

    bool operator !=(const dst_iterator<Iterator> &oth) const {
        return !(*this == oth);
    }

    bool operator <(const dst_iterator<Iterator> &oth) const {
        return ite < oth.ite;
    }

    bool operator >(const dst_iterator<Iterator> &oth) const {
        return ite > oth.ite;
    }

    bool operator <=(const dst_iterator<Iterator> &oth) const {
        return ite <= oth.ite;
    }

    bool operator >=(const dst_iterator<Iterator> &oth) const {
        return ite >= oth.ite;
    }

    const Node& operator *() {
        return ite->first;
    }

    const Node& operator *() const {
        return ite->first;
    }

    dst_iterator operator ++() {
        ++ite;
        return ite;
    }
};

class dst_iteration {
    using ite_type = vec<Edge>::const_iterator;
    const vec<Edge> &edges;

public:
    dst_iteration(const vec<Edge> &edges) : edges(edges) { }

    auto begin() const {
        return dst_iterator<ite_type>(edges.cbegin());
    }

    auto end() const {
        return dst_iterator<ite_type>(edges.cend());
    }
};

dst_iteration dst(const vec<Edge> &edges) {
    return dst_iteration(edges);
}

}

namespace graph {

using Capacity = ll;

struct FlowEdge : public std::tuple<Node, Capacity, ll, Weight> {
    using std::tuple<Node, Capacity, ll, Weight>::tuple;

    Node& to() {
        return std::get<0>(*this);
    }

    const Node& to() const {
        return std::get<0>(*this);
    }

    Capacity& cap() {
        return std::get<1>(*this);
    }

    const Capacity& cap() const {
        return std::get<1>(*this);
    }

    ll& rev_idx() {
        return std::get<2>(*this);
    }

    const ll& rev_idx() const {
        return std::get<2>(*this);
    }

    Weight& weight() {
        return std::get<3>(*this);
    }

    const Weight& weight() const {
        return std::get<3>(*this);
    }
};

template <bool Directed>
struct FlowGraph : public vvec<FlowEdge> {
    using vvec<FlowEdge>::vvec;

    void add_edge(Node f, Node t, Capacity c = 1, Weight w = 1) {
        add_edge_with_rev(f, t, c, w);
        if (!Directed) add_edge_with_rev(t, f, c, w);
    }

private:
    void add_edge_with_rev(Node f, Node t, Capacity c, Weight w) {
        FlowEdge fe(t, c, (ll)((*this)[t].size()), w);
        (*this)[f].push_back(fe);
        FlowEdge rfe(f, Capacity(), (ll)((*this)[f].size()) - 1, -w);
        (*this)[t].push_back(rfe);
    }
};

}

namespace flow {

using graph::Node;
using graph::Capacity;

const Capacity cinf = 5e15;
const ll dinf = 5e15;

}

namespace flow {

template <template <typename> typename Solver, 
          typename FlowGraph = graph::FlowGraph<true>,
          bool Restore = false>
class BipartiteMatching {
    using matching = std::pair<Node, Node>;
    ssize_t asz, bsz;
    FlowGraph fg, res;
    Node src, sink;
    std::set<std::tuple<Node, Node, ll>> edges;

    vec<matching> extract_() {
        vec<matching> ret;
        for (auto &&e : edges) {
            Node f, t;
            ll idx;
            std::tie(f, t, idx) = e;
            auto c = res[f][idx].cap();
            if (c == 0) ret.emplace_back(f, t - asz);
        }
        return ret;
    }

public:
    BipartiteMatching(ssize_t asz, ssize_t bsz)
        : asz(asz), bsz(bsz), fg(asz + bsz + 2), src(asz + bsz), sink(asz + bsz + 1)
    {
        for (ll i = 0; i < asz; i++) fg.add_edge(src, i, 1);
        for (ll i = 0; i < bsz; i++) fg.add_edge(i + asz, sink, 1);
    }

    void add_edge(Node f, Node t) {
        fg.add_edge(f, t + asz, 1);
        if (Restore) edges.emplace(f, t + asz, fg[f].size() - 1);
    }

    ll solve() {
        Solver<FlowGraph> solver(fg);
        auto ret = solver.max_flow(src, sink);
        if (Restore) res = std::move(solver.graph());
        return ret;
    }

    vec<matching> extract() {
        if (Restore) {
            return extract_();
        } else {
            assert(false);
        }
    }

};

}

namespace flow {

template <typename FlowGraph = graph::FlowGraph<true>>
class Dinic {
    FlowGraph flow_graph;
    vec<ll> dists;
    vec<ssize_t> used;
    Node src, sink;

    void bfs(Node start) {
        vec<ll> dists(flow_graph.size(), dinf);
        dists[start] = 0;
        std::queue<std::pair<ll, Node>> que;
        que.emplace(0, start);
        while (que.size()) {
            ll d;
            Node cur;
            std::tie(d, cur) = que.front();
            que.pop();
            for (const auto &e : flow_graph[cur]) {
                Node nxt;
                Capacity cap;
                tie(nxt, cap, std::ignore, std::ignore) = e;
                if (cap <= Capacity()) continue;
                if (dists[nxt] <= d + 1) continue;
                dists[nxt] = d + 1;
                que.emplace(d + 1, nxt);
            }
        }
        this->dists = move(dists);
    }

    Capacity dfs(Node cur, Node pre, Capacity flow) {
        if (cur == sink) return flow;
        for (auto idx = used[cur] + 1; idx < flow_graph[cur].size(); idx++) {
            used[cur]++;
            auto &e = flow_graph[cur][idx];
            if (dists[e.to()] <= dists[cur]) continue;
            if (e.cap() <= Capacity()) continue;
            if (e.to() == pre) continue;
            auto f = dfs(e.to(), cur, std::min(flow, e.cap()));
            e.cap() -= f;
            flow_graph[e.to()][e.rev_idx()].cap() += f;
            if (Capacity() < f) return f;
        }
        return Capacity();
    }

public:
    Dinic(const FlowGraph &flow_graph) :
        flow_graph(flow_graph), used(flow_graph.size()) { }

    Capacity max_flow(Node src, Node sink) {
        this->src = src;
        this->sink = sink;
        auto ret = Capacity();
        while (true) {
            bfs(src);
            if (dists[sink] == dinf) break;
            std::fill(ALL(used), -1);
            while (true) {
                auto tmp = dfs(src, -1, cinf);
                if (tmp == Capacity()) break;
                ret += tmp;
            }
        }
        return ret;
    }

    FlowGraph graph() {
        return flow_graph;
    }
};

}

int main() {
    ll n, m;
    std::cin >> n >> m;
    auto am = make_v<ll>(0, n, m);
    for (auto &&v : am) for (auto &&e : v) {
        std::cin >> e;
        e--;
    }
    auto bm = am;

    std::map<pll, std::set<ll>> edges;
    for (ll i = 0; i < n; i++) for (ll j = 0; j < m; j++) {
        ll v = am[i][j];
        edges[pll(i, v / m)].insert(v);
    }
    for (ll i = 0; i < m; i++) {
        flow::BipartiteMatching<flow::Dinic, graph::FlowGraph<true>, true> bim(n, n);
        for (auto &&e : edges) {
            ll a, b;
            std::tie(a, b) = e.first;
            bim.add_edge(a, b);
        }
        bim.solve();
        auto res = std::move(bim.extract());
        for (auto &&e : res) {
            ll a, b;
            std::tie(a, b) = e;
            auto &st = edges[pll(a, b)];
            bm[a][i] = *st.begin();
            st.erase(st.begin());
            if (st.empty()) edges.erase(pll(a, b));
        }
    }

    auto output = [&] {
        for (ll i = 0; i < n; i++) for (ll j = 0; j < m; j++) std::cout << bm[i][j] + 1 << " \n"[j + 1 == m];
    };

    output();

    for (ll j = 0; j < m; j++) {
        vec<ll> tmp(n);
        for (ll i = 0; i < n; i++) tmp[i] = bm[i][j];
        std::sort(ALL(tmp));
        for (ll i = 0; i < n; i++) bm[i][j] = tmp[i];
    }

    output();

    return 0;
}


Measured memory_bytes: 4736