import java.io.*;
import java.util.*;

public class TestsGen {

    private static Random rand = new Random("chocolate".hashCode());

    class Test {
        int n, m;
        int[][] a;

        public Test(int n, int m, int[][] a) {
            this.n = n;
            this.m = m;
            if ((n & m & 1) == 1) {
                throw new AssertionError("invalid test: n * m is not even");
            }
            this.a = a;
        }

        void printTest() {
            ++numOfTest;
            try {
                System.err.println("Generating test #" + numOfTest);
                PrintWriter out = new PrintWriter(numOfTest / 10 + ""
                        + numOfTest % 10);
                out.println(n + " " + m);
                for (int i = 0; i < n; i++) {
                    for (int j = 0; j < m; j++) {
                        if (j > 0) {
                            out.print(" ");
                        }
                        out.print(a[i][j]);
                    }
                    out.println();
                }
                out.close();
            } catch (Exception e) {
                System.err.println("failed to print test");
                System.exit(1);
            }
        }
    }

    int numOfTest;

    public static void main(String[] args) {
        new TestsGen().run();
    }

    void run() {
        numOfTest = 0;
        // 1st Sample Test
        new Test(2, 3, new int[][] { { 1, 1, 2 }, { 3, 3, 2 } }).printTest();
        // 2nd Sample Test
        new Test(5, 6, new int[][] { { 1, 2, 2, 3, 3, 4 },
                { 1, 5, 6, 7, 7, 4 }, { 8, 5, 6, 9, 10, 10 },
                { 8, 11, 11, 9, 12, 13 }, { 14, 14, 15, 15, 12, 13 } })
                .printTest();
        new Test(1, 2, new int[][] { { 1, 1 } }).printTest();
        new Test(2, 1, new int[][] { { 1 }, { 1 } }).printTest();
        genRandomTest(20, 20).printTest();
        genRandomTest(20, 19).printTest();
        genRandomTest(19, 20).printTest();
        genNoTest(20, 20).printTest();
        genNoTest(20, 19).printTest();
        genNoTest(19, 20).printTest();
        for (int i = 0; i < 20; i++) {
            int x, y;
            {
                do {
                    x = rand.nextInt(20) + 1;
                    y = rand.nextInt(20) + 1;
                } while ((x & y & 1) == 1);
                genRandomTest(x, y).printTest();
            }
            {
                do {
                    x = rand.nextInt(16) + 5;
                    y = rand.nextInt(16) + 5;
                } while ((x & y & 1) == 1);
                genNoTest(x, y).printTest();
            }
        }
    }

    Test genRandomTest(int n, int m) {
        int[][] a;
        do {
            a = new int[n][m];
            a = new Graph(a).getPerfectMatching(0);
        } while (a == null);
        return new Test(n, m, a);
    }

    Test genNoTest(int n, int m) {
        int[][] a;
        int cur;
        loop: do {
            cur = 0;
            a = new int[n][m];
            for (int i = 0; i + 1 < n; i++) {
                int x;
                int cnt = 0;
                do {
                    x = rand.nextInt(m);
                    cnt++;
                    if (cnt > 100) {
                        break;
                    }
                } while (a[i][x] != 0 || a[i + 1][x] != 0);
                if (cnt > 100) {
                    a = null;
                    continue loop;
                }
                a[i + 1][x] = a[i][x] = ++cur;
            }
            for (int i = 0; i + 1 < m; i++) {
                int x;
                int cnt = 0;
                do {
                    x = rand.nextInt(n);
                    cnt++;
                    if (cnt > 100) {
                        break;
                    }
                } while (a[x][i] != 0 || a[x][i + 1] != 0);
                if (cnt > 100) {
                    a = null;
                    continue loop;
                }
                a[x][i + 1] = a[x][i] = ++cur;
            }
            a = new Graph(a).getPerfectMatching(cur);
        } while (a == null);
        return new Test(n, m, a);
    }

    class Graph {
        ArrayList<Integer>[] edges;
        int[] p;
        boolean[] was;
        int n;
        int m;
        int[][] b;
        int[][] a;

        public Graph(int[][] a) {
            this.a = a;
            b = new int[a.length][];
            for (int i = 0; i < a.length; i++) {
                b[i] = new int[a[i].length];
                Arrays.fill(b[i], -1);
                for (int j = 0; j < a[i].length; j++) {
                    if (a[i][j] != 0) {
                        continue;
                    }
                    if (((i ^ j) & 1) == 0) {
                        b[i][j] = n;
                        ++n;
                    } else {
                        b[i][j] = m;
                        ++m;
                    }
                }
            }
            ArrayList<Integer> perm = new ArrayList<Integer>();
            for (int i = 0; i < n; i++) {
                perm.add(i);
            }
            Collections.shuffle(perm, rand);
            for (int i = 0; i < a.length; i++) {
                for (int j = (i & 1); j < a[i].length; j += 2) {
                    if (a[i][j] == 0) {
                        b[i][j] = perm.get(b[i][j]);
                    }
                }
            }
            edges = new ArrayList[n];
            for (int i = 0; i < edges.length; i++) {
                edges[i] = new ArrayList<Integer>();
            }
            p = new int[m];
            Arrays.fill(p, -1);
            for (int i = 0; i < a.length; i++) {
                for (int j = (i & 1); j < a[i].length; j += 2) {
                    if (a[i][j] != 0) {
                        continue;
                    }
                    for (int dir = 0; dir < DX.length; dir++) {
                        int x = i + DX[dir];
                        int y = j + DY[dir];
                        if (x < 0 || y < 0 || x >= a.length || y >= a[x].length
                                || a[x][y] != 0) {
                            continue;
                        }
                        edges[b[i][j]].add(b[x][y]);
                    }
                }
            }
        }

        int[][] getPerfectMatching(int cur) {
            if (n != m) {
                return null;
            }
            was = new boolean[n];
            for (int i = 0; i < n; i++) {
                Arrays.fill(was, false);
                if (!dfs(i)) {
                    return null;
                }
            }
            for (int i = 0; i < a.length; i++) {
                for (int j = (i & 1) ^ 1; j < a[i].length; j += 2) {
                    if (a[i][j] != 0) {
                        continue;
                    }
                    int z = p[b[i][j]];
                    for (int dir = 0; dir < DX.length; dir++) {
                        int x = i + DX[dir];
                        int y = j + DY[dir];
                        if (x < 0 || y < 0 || x >= a.length || y >= a[x].length
                                || a[x][y] != 0) {
                            continue;
                        }
                        if (b[x][y] == z) {
                            a[x][y] = a[i][j] = ++cur;
                            break;
                        }
                    }
                }
            }
            return a;
        }

        boolean dfs(int x) {
            if (was[x]) {
                return false;
            }
            was[x] = true;
            for (int i : edges[x]) {
                if (p[i] == -1 || dfs(p[i])) {
                    p[i] = x;
                    return true;
                }
            }
            return false;
        }
    }

    final int[] DX = { 1, 0, -1, 0 };
    final int[] DY = { 0, 1, 0, -1 };
}
