import java.io.*; import java.util.*; import java.text.*; import java.math.*; import java.util.regex.*; public class Solution { private static int chessBoardSize; private static BfsAlgorithm bfsAlgo = new BfsAlgorithm(); private static Vertex vEnd; public static void main(String[] args) { Scanner in = new Scanner(System.in); chessBoardSize = in.nextInt(); vEnd = new Vertex(chessBoardSize - 1, chessBoardSize - 1); for (int i = 1; i < chessBoardSize; i++) { for (int j = 1; j < chessBoardSize; j++) { Vertex vRoot = generateGraph(j, i); System.out.print(findShortestPath(vRoot, vEnd) + " "); } System.out.print("\n"); } } // generate graph private static Vertex generateGraph(int moveA, int moveB) { ArrayList vertexes = new ArrayList(); for (int i = 0; i < chessBoardSize; i++) { for (int j = 0; j < chessBoardSize; j++) { vertexes.add(new Vertex(i, j)); } } // for each vertex, create adjacency list for (Vertex v : vertexes) { if (v.getAdjVertices().isEmpty()) { createAdjList(v, vertexes, moveA, moveB); } } // return root vertex return vertexes.get(0); } // create adjacency list for a vertex private static void createAdjList(Vertex v, ArrayList vertexes, int moveA, int moveB) { int xRightA = v.getX() + moveA; int xRightB = v.getX() + moveB; int xLeftA = v.getX() - moveA; int xLeftB = v.getX() - moveB; int yUpA = v.getY() + moveA; int yUpB = v.getY() + moveB; int yDownA = v.getY() - moveA; int yDownB = v.getY() - moveB; // all possible moves of the knight createAdjVertex(v, vertexes, xRightA, yUpB); createAdjVertex(v, vertexes, xRightB, yUpA); createAdjVertex(v, vertexes, xRightA, yDownB); createAdjVertex(v, vertexes, xRightB, yDownA); createAdjVertex(v, vertexes, xLeftA, yUpB); createAdjVertex(v, vertexes, xLeftB, yUpA); createAdjVertex(v, vertexes, xLeftA, yDownB); createAdjVertex(v, vertexes, xLeftB, yDownA); } // add an adjacent vertex private static void createAdjVertex(Vertex v, ArrayList vertexes, int x, int y) { // check if new position is in bounds if (x < chessBoardSize && y < chessBoardSize && x >= 0 && y >= 0) { int vIndex = vertexes.indexOf(new Vertex(x, y)); // keep index to reused same vertex Vertex adjVertex = vertexes.get(vIndex); v.addAdjVertex(adjVertex); } } // find shortest path between and return amount of turns to reach private static int findShortestPath(Vertex start, Vertex end) { List pathList = new ArrayList(); final HashMap mapParentChild = new HashMap(); bfsAlgo.run(start, new BfsAlgorithm.BfsAction() { private Vertex currentParent; @Override public boolean onVisitParent(Vertex parent) { currentParent = parent; return false; } @Override public boolean onVisitChild(Vertex child) { mapParentChild.put(child, currentParent); if (child.equals(end)) { return true; } else { return false; } } }); pathList.add(end); Vertex vParent = mapParentChild.get(end); /*for (Map.Entry entry : mapParentChild.entrySet()) { System.out.println("map : " + entry.getKey() + ", " + entry.getValue()); }*/ while (vParent != null) { pathList.add(vParent); vParent = mapParentChild.get(vParent); } Collections.reverse(pathList); int result = -1; if (pathList.size() - 1 != 0) { // path found result = pathList.size() - 1; } return result; } private static String pathToString(List path) { StringBuilder sb = new StringBuilder(); for (int i = 0; i < path.size(); i++) { Vertex v = path.get(i); if (i != 0) sb.append("->"); sb.append(v.getName()); } return sb.toString(); } } // BFS algorithm class BfsAlgorithm { public void run(Vertex v, BfsAction action) { List visitedList = new ArrayList(); Queue q = new LinkedList(); q.add(v); v.setVisited(true); visitedList.add(v); while (!q.isEmpty()) { Vertex vertex = (Vertex) q.poll(); if (action.onVisitParent(vertex)) { break; } for (Vertex vAdj : vertex.getAdjVertices()) { if (!vAdj.isVisited()) { vAdj.setVisited(true); visitedList.add(vAdj); q.add(vAdj); if (action.onVisitChild(vAdj)) { q = new LinkedList(); break; } } } } // reset vertexes for (Vertex vert : visitedList) { vert.setVisited(false); } } public interface BfsAction { boolean onVisitParent(Vertex v); boolean onVisitChild(Vertex v); } } // represents a graph vertex (node) class Vertex { private final int x, y; private String name; private boolean visited; private LinkedList adjVertices = new LinkedList(); // adjacency list of vertices public Vertex(int x, int y) { this.x = x; this.y = y; name = "(" + x + ", " + y + ")"; } public int getX() { return x; } public int getY() { return y; } public LinkedList getAdjVertices() { return adjVertices; } public void addAdjVertex(Vertex v) { adjVertices.add(v); } public String getName() { return name; } public boolean isVisited() { return visited; } public void setVisited(boolean visited) { this.visited = visited; } @Override public String toString() { return name; } @Override public boolean equals(Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; Vertex vertex = (Vertex) o; if (x != vertex.x) return false; return y == vertex.y; } @Override public int hashCode() { int result = x; result = 37 * result + y; return result; } }