use std::io::*;
use std::str::FromStr;

fn read<T: FromStr>() -> T {
    let stdin = stdin();
    let stdin = stdin.lock();
    let token: String = stdin
        .bytes()
        .map(|c| c.expect("failed to read char") as char)
        .skip_while(|c| c.is_whitespace())
        .take_while(|c| !c.is_whitespace())
        .collect();
    token.parse().ok().expect("failed to parse token")
}

//
// HK
//

struct BipartiteMatchingResult {
    left_to_right: Vec<Option<usize>>,
    right_to_left: Vec<Option<usize>>,
    num_matches: usize
}

fn hopcroft_karp(adj: &Vec<Vec<usize>>, num_r_vs: usize) -> BipartiteMatchingResult {
    use std::collections::VecDeque;

    let num_l_vs = adj.len();
    let mut usd = vec![false; num_l_vs];
    let mut mat = vec![num_l_vs; num_r_vs];

    fn augment(
        l: usize,
        adj: &Vec<Vec<usize>>,
        lev: &Vec<i32>,
        vis: &mut Vec<bool>,
        mat: &mut Vec<usize>,
    ) -> bool {
        let num_l_vs = adj.len();
        if l == num_l_vs {
            return true;
        }
        if vis[l] {
            return false;
        }
        vis[l] = true;
        for &r in adj[l].iter() {
            let l2 = mat[r];
            if lev[l2] > lev[l] && augment(l2, adj, lev, vis, mat) {
                mat[r] = l;
                return true;
            }
        }
        return false;
    }

    loop {
        let mut lev: Vec<i32> = vec![-1; num_l_vs + 1];
        lev[num_l_vs] = num_r_vs as i32;
        let mut que: VecDeque<usize> = VecDeque::new();

        for l in 0..num_l_vs {
            if !usd[l] {
                que.push_back(l);
                lev[l] = 0;
            }
        }

        while let Some(l) = que.pop_front() {
            for &r in adj[l].iter() {
                let l2 = mat[r];
                if lev[l2] < 0 {
                    lev[l2] = lev[l] + 1;
                    que.push_back(l2);
                }
            }
        }

        let mut vis = vec![false; num_l_vs];
        let mut update = false;
        for l in 0..num_l_vs {
            if !usd[l] && augment(l, adj, &lev, &mut vis, &mut mat) {
                usd[l] = true;
                update = true;
            }
        }

        if !update {
            break;
        }
    }

    // Generate result
    let mut left_to_right = vec![None; num_l_vs];
    let mut right_to_left = vec![None; num_r_vs];
    let mut num_matches = 0;
    for r in 0..num_r_vs {
        if mat[r] == num_l_vs {
            continue;
        }
        left_to_right[mat[r]] = Some(r);
        right_to_left[r] = Some(mat[r]);
        num_matches += 1;
    }
    BipartiteMatchingResult {
        left_to_right: left_to_right,
        right_to_left: right_to_left,
        num_matches: num_matches
    }
}

fn show(a: &Vec<Vec<usize>>) {
    for row in a.iter() {
        for val in row.iter() {
            print!("{} ", val + 1)
        }
        println!();
    }
}

fn transpose(a: &Vec<Vec<usize>>) -> Vec<Vec<usize>> {
    let mut b = vec![vec![0; a.len()]; a[0].len()];
    for y in 0..a.len() {
        for x in 0..a[0].len() {
            b[x][y] = a[y][x];
        }
    }
    return b;
}

fn main() {
    let h: usize = read();
    let w: usize = read();
    let a: Vec<Vec<usize>> = (0..h)
        .map(|_| (0..w).map(|_| read::<usize>() - 1).collect())
        .collect();

    // first step
    let mut b = vec![vec![!0; w]; h];
    {
        let mut cnt = vec![vec![0; h]; h];
        for y in 0..h {
            for x in 0..w {
                cnt[y][a[y][x] / w] += 1;
            }
        }

        let mut usd = vec![vec![false; w]; h];
        for x in 0..w {
            let mut adj = vec![vec![]; h];

            for y in 0..h {
                for r in 0..h {
                    if cnt[y][r] > 0 {
                        adj[r].push(y);
                    }
                }
            }

            //eprintln!("cnt {:?}", &cnt);
            let mat = hopcroft_karp(&adj, h);
            //eprintln!("{:?}", &mat);

            for y in 0..h {
                let r = mat.right_to_left[y].unwrap();
                cnt[y][r] -= 1;
                for ax in 0..w {
                    if !usd[y][ax] && a[y][ax] / w == r {
                        b[y][x] = a[y][ax];
                        usd[y][ax] = true;
                        break;
                    }
                }
            }
        }
    }
    let b = b;
    show(&b);

    // second step
    let mut t: Vec<Vec<usize>> = transpose(&b);
    for row in t.iter_mut() {
        row.sort();
    }
    let c = transpose(&t);
    show(&c);
}


Measured memory_bytes: 4352