diff --git a/Backtracking/NQueens.java b/Backtracking/NQueens.java new file mode 100644 index 000000000..597e35a2f --- /dev/null +++ b/Backtracking/NQueens.java @@ -0,0 +1,136 @@ +package Backtracking; + +import java.util.ArrayList; +import java.util.List; + +/** + * Problem statement: + * Given a N x N chess board. Return all arrangements in which N queens can be placed on the board such no two queens attack + * each other. + * Ex. N = 6 + * Solution= There are 4 possible ways + * Arrangement: 1 + * ".Q....", + * "...Q..", + * ".....Q", + * "Q.....", + * "..Q...", + * "....Q." + *

+ * Arrangement: 2 + * "..Q...", + * ".....Q", + * ".Q....", + * "....Q.", + * "Q.....", + * "...Q.." + *

+ * Arrangement: 3 + * "...Q..", + * "Q.....", + * "....Q.", + * ".Q....", + * ".....Q", + * "..Q..." + *

+ * Arrangement: 4 + * "....Q.", + * "..Q...", + * "Q.....", + * ".....Q", + * "...Q..", + * ".Q...." + * + * Solution: + * Brute Force approach: + * + * Generate all possible arrangement to place N queens on N*N board. + * Check each board if queens are placed safely. + * If it is safe, include arrangement in solution set. Otherwise ignore it + * + * Optimized solution: + * This can be solved using backtracking in below steps + * + * Start with first column and place queen on first row + * Try placing queen in a row on second column + * If placing second queen in second column attacks any of the previous queens, change the row in second column + * otherwise move to next column and try to place next queen + * In case if there is no rows where a queen can be placed such that it doesn't attack previous queens, then go back to previous column and change row of previous queen. + * Keep doing this until last queen is not placed safely. + * If there is no such way then return an empty list as solution + */ +public class NQueens { + + public static void main(String[] args) { + placeQueens(1); + placeQueens(2); + placeQueens(3); + placeQueens(4); + placeQueens(5); + placeQueens(6); + } + + public static void placeQueens(final int queens) { + List> arrangements = new ArrayList>(); + getSolution(queens, arrangements, new int[queens], 0); + if (arrangements.isEmpty()) { + System.out.println("There is no way to place " + queens + " queens on board of size " + queens + "x" + queens); + } else { + System.out.println("Arrangement for placing " + queens + " queens"); + } + arrangements.forEach(arrangement -> { + arrangement.forEach(row -> System.out.println(row)); + System.out.println(); + }); + } + + /** + * This is backtracking function which tries to place queen recursively + * @param boardSize: size of chess board + * @param solutions: this holds all possible arrangements + * @param columns: columns[i] = rowId where queen is placed in ith column. + * @param columnIndex: This is the column in which queen is being placed + */ + private static void getSolution(int boardSize, List> solutions, int[] columns, int columnIndex) { + if (columnIndex == boardSize) { + // this means that all queens have been placed + List sol = new ArrayList(); + for (int i = 0; i < boardSize; i++) { + StringBuilder sb = new StringBuilder(); + for (int j = 0; j < boardSize; j++) { + sb.append(j == columns[i] ? "Q" : "."); + } + sol.add(sb.toString()); + } + solutions.add(sol); + return; + } + + // This loop tries to place queen in a row one by one + for (int rowIndex = 0; rowIndex < boardSize; rowIndex++) { + columns[columnIndex] = rowIndex; + if (isPlacedCorrectly(columns, rowIndex, columnIndex)) { + // If queen is placed successfully at rowIndex in column=columnIndex then try placing queen in next column + getSolution(boardSize, solutions, columns, columnIndex + 1); + } + } + } + + /** + * This function checks if queen can be placed at row = rowIndex in column = columnIndex safely + * @param columns: columns[i] = rowId where queen is placed in ith column. + * @param rowIndex: row in which queen has to be placed + * @param columnIndex: column in which queen is being placed + * @return true: if queen can be placed safely + * false: otherwise + */ + private static boolean isPlacedCorrectly(int[] columns, int rowIndex, int columnIndex) { + for (int i = 0; i < columnIndex; i++) { + int diff = Math.abs(columns[i] - rowIndex); + if (diff == 0 || columnIndex - i == diff) { + return false; + } + } + return true; + } +}