import java.io.*; import java.util.*; // Represents a position of the KnightL on the chessboard. Note instances are immutable once created. class Position { private int x; private int y; private Position parent; public Position(int x, int y, Position parent) { this.x = x; this.y = y; this.parent = parent; } public Position(int x, int y) { this(x, y, null); } public int getX() { return this.x; } public int getY() { return this.y; } public Position getParent() { return this.parent; } public void setParent(Position parent) { this.parent = parent; } @Override public boolean equals(Object o) { if (o instanceof Position) { Position p = (Position)o; return (p.x == this.x && p.y == this.y); } else { return false; } } @Override public int hashCode() { return Integer.hashCode(x) * Integer.hashCode(y); } } public class Solution { // Returns the minimum number of moves a KnightL(a,b) must make to cross a chessboard of size n x n. private static int getMinimumMoveCount(int n, int a, int b) { int moveCount = -1; boolean targetReached = false; Set visited = new HashSet<>(); Deque nextPositions = new ArrayDeque<>(); Position targetPosition = new Position(n - 1, n - 1, null); Position startPosition = new Position(0, 0, null); nextPositions.add(startPosition); Position currentPosition = null; while (nextPositions.peek() != null) { currentPosition = nextPositions.poll(); // If this is the target square, we're done searching if (currentPosition.equals(targetPosition)) { targetReached = true; break; } // Otherwise, add every legal move to the set of next positions to evaluate int curX = currentPosition.getX(); int curY = currentPosition.getY(); Position[] moves = new Position[8]; moves[0] = new Position(curX + a, curY - b); moves[1] = new Position(curX + a, curY + b); moves[2] = new Position(curX - a, curY - b); moves[3] = new Position(curX - a, curY + b); moves[4] = new Position(curX + b, curY - a); moves[5] = new Position(curX + b, curY + a); moves[6] = new Position(curX - b, curY - a); moves[7] = new Position(curX - b, curY + a); for (Position nextPosition : moves) { int x = nextPosition.getX(); int y = nextPosition.getY(); if ((x >= 0 && y >= 0 && x < n && y < n) && !visited.contains(nextPosition)) { nextPosition.setParent(currentPosition); visited.add(nextPosition); nextPositions.add(nextPosition); } } } // If we reached the target square, report how many moves it took us if (targetReached) { do { currentPosition = currentPosition.getParent(); moveCount += 1; } while (currentPosition != null); } return moveCount; } public static void main(String[] args) { Scanner in = new Scanner(System.in); int n = in.nextInt(); // Create our table of memoized minimum move counts int[][] minimumMoveCounts = new int[n][n]; for (int i = 1; i < n; i++) { for (int j = 1; j < n; j++) { int minimumMoveCount; if (i > 1 && j < i) { minimumMoveCount = minimumMoveCounts[j - 1][i - 1]; } else { minimumMoveCount = getMinimumMoveCount(n, i, j); minimumMoveCounts[i - 1][j - 1] = minimumMoveCount; } System.out.print(minimumMoveCount); if (j < (n - 1)) System.out.print(" "); } System.out.println(); } } }