 Open in App
Not now

# N-Queen Problem | Local Search using Hill climbing with random neighbour

• Difficulty Level : Expert
• Last Updated : 24 Mar, 2023

The N Queen is the problem of placing N chess queens on an N×N chessboard so that no two queens attack each other.
For example, the following is a solution for 8 Queen problem. Input: N = 4
Output:
0 1 0 0
0 0 0 1
1 0 0 0
0 0 1 0
Explanation:
The Position of queens are:
1 – {1, 2}
2 – {2, 4}
3 – {3, 1}
4 – {4, 3}
As we can see that we have placed all 4 queens
in a way that no two queens are attacking each other.
So, the output is correct

Input: N = 8
Output:
0 0 0 0 0 0 1 0
0 1 0 0 0 0 0 0
0 0 0 0 0 1 0 0
0 0 1 0 0 0 0 0
1 0 0 0 0 0 0 0
0 0 0 1 0 0 0 0
0 0 0 0 0 0 0 1
0 0 0 0 1 0 0 0

Approach: The idea is to use Hill Climbing Algorithm

• While there are algorithms like Backtracking to solve N Queen problem, let’s take an AI approach in solving the problem.
• It’s obvious that AI does not guarantee a globally correct solution all the time but it has quite a good success rate of about 97% which is not bad.
• A description of the notions of all terminologies used in the problem will be given and are as follows:-
• Notion of a State – A state here in this context is any configuration of the N queens on the N X N board. Also, in order to reduce the search space let’s add an additional constraint that there can only be a single queen in a particular column. A state in the program is implemented using an array of length N, such that if state[i]=j then there is a queen at column index i and row index j.
• Notion of Neighbours – Neighbours of a state are other states with board configuration that differ from the current state’s board configuration with respect to the position of only a single queen. This queen that differs a state from its neighbour may be displaced anywhere in the same column.
• Optimisation function or Objective function – We know that local search is an optimization algorithm that searches the local space to optimize a function that takes the state as input and gives some value as an output. The value of the objective function of a state here in this context is the number of pairs of queens attacking each other. Our goal here is to find a state with the minimum objective value. This function has a maximum value of NC2 and a minimum value of 0.

Algorithm:

1. Start with a random state(i.e, a random configuration of the board).
2. Scan through all possible neighbours of the current state and jump to the neighbour with the highest objective value, if found any. If there does not exist, a neighbour, with objective strictly higher than the current state but there exists one with equal then jump to any random neighbour(escaping shoulder and/or local optimum).
3. Repeat step 2, until a state whose objective is strictly higher than all it’s neighbour’s objectives, is found and then go to step 4.
4. The state thus found after the local search is either the local optimum or the global optimum. There is no way of escaping local optima but adding a random neighbour or a random restart each time a local optimum is encountered increases the chances of achieving global optimum(the solution to our problem).
5. Output the state and return.
• It is easily visible that the global optimum in our case is 0 since it is the minimum number of pairs of queens that can attack each other. Also, the random restart has a higher chance of achieving global optimum but we still use random neighbour because our problem of N queens does not has a high number of local optima and random neighbour is faster than random restart.
• Conclusion:
1. Random Neighbour escapes shoulders but only has a little chance of escaping local optima.
2. Random Restart both escapes shoulders and has a high chance of escaping local optima.

Below is the implementation of the Hill-Climbing algorithm:

## CPP

 `// C++ implementation of the ` `// above approach ` `#include ` `#include ` ` `  `#define N 8 ` `using` `namespace` `std; ` ` `  `// A utility function that configures ` `// the 2D array "board" and ` `// array "state" randomly to provide ` `// a starting point for the algorithm. ` `void` `configureRandomly(``int` `board[][N], ` `                       ``int``* state) ` `{ ` ` `  `    ``// Seed for the random function ` `    ``srand``(``time``(0)); ` ` `  `    ``// Iterating through the ` `    ``// column indices ` `    ``for` `(``int` `i = 0; i < N; i++) { ` ` `  `        ``// Getting a random row index ` `        ``state[i] = ``rand``() % N; ` ` `  `        ``// Placing a queen on the ` `        ``// obtained place in ` `        ``// chessboard. ` `        ``board[state[i]][i] = 1; ` `    ``} ` `} ` ` `  `// A utility function that prints ` `// the 2D array "board". ` `void` `printBoard(``int` `board[][N]) ` `{ ` ` `  `    ``for` `(``int` `i = 0; i < N; i++) { ` `        ``cout << ``" "``; ` `        ``for` `(``int` `j = 0; j < N; j++) { ` `            ``cout << board[i][j] << ``" "``; ` `        ``} ` `        ``cout << ``"\n"``; ` `    ``} ` `} ` ` `  `// A utility function that prints ` `// the array "state". ` `void` `printState(``int``* state) ` `{ ` ` `  `    ``for` `(``int` `i = 0; i < N; i++) { ` `        ``cout << ``" "` `<< state[i] << ``" "``; ` `    ``} ` `    ``cout << endl; ` `} ` ` `  `// A utility function that compares ` `// two arrays, state1 and state2 and ` `// returns true if equal ` `// and false otherwise. ` `bool` `compareStates(``int``* state1, ` `                   ``int``* state2) ` `{ ` ` `  `    ``for` `(``int` `i = 0; i < N; i++) { ` `        ``if` `(state1[i] != state2[i]) { ` `            ``return` `false``; ` `        ``} ` `    ``} ` `    ``return` `true``; ` `} ` ` `  `// A utility function that fills ` `// the 2D array "board" with ` `// values "value" ` `void` `fill(``int` `board[][N], ``int` `value) ` `{ ` `    ``for` `(``int` `i = 0; i < N; i++) { ` `        ``for` `(``int` `j = 0; j < N; j++) { ` `            ``board[i][j] = value; ` `        ``} ` `    ``} ` `} ` ` `  `// This function calculates the ` `// objective value of the ` `// state(queens attacking each other) ` `// using the board by the ` `// following logic. ` `int` `calculateObjective(``int` `board[][N], ` `                       ``int``* state) ` `{ ` ` `  `    ``// For each queen in a column, we check ` `    ``// for other queens falling in the line ` `    ``// of our current queen and if found, ` `    ``// any, then we increment the variable ` `    ``// attacking count. ` ` `  `    ``// Number of queens attacking each other, ` `    ``// initially zero. ` `    ``int` `attacking = 0; ` ` `  `    ``// Variables to index a particular ` `    ``// row and column on board. ` `    ``int` `row, col; ` ` `  `    ``for` `(``int` `i = 0; i < N; i++) { ` ` `  `        ``// At each column 'i', the queen is ` `        ``// placed at row 'state[i]', by the ` `        ``// definition of our state. ` ` `  `        ``// To the left of same row ` `        ``// (row remains constant ` `        ``// and col decreases) ` `        ``row = state[i], col = i - 1; ` `        ``while` `(col >= 0 ` `               ``&& board[row][col] != 1) { ` `            ``col--; ` `        ``} ` `        ``if` `(col >= 0 ` `            ``&& board[row][col] == 1) { ` `            ``attacking++; ` `        ``} ` ` `  `        ``// To the right of same row ` `        ``// (row remains constant ` `        ``// and col increases) ` `        ``row = state[i], col = i + 1; ` `        ``while` `(col < N ` `               ``&& board[row][col] != 1) { ` `            ``col++; ` `        ``} ` `        ``if` `(col < N ` `            ``&& board[row][col] == 1) { ` `            ``attacking++; ` `        ``} ` ` `  `        ``// Diagonally to the left up ` `        ``// (row and col simultaneously ` `        ``// decrease) ` `        ``row = state[i] - 1, col = i - 1; ` `        ``while` `(col >= 0 && row >= 0 ` `               ``&& board[row][col] != 1) { ` `            ``col--; ` `            ``row--; ` `        ``} ` `        ``if` `(col >= 0 && row >= 0 ` `            ``&& board[row][col] == 1) { ` `            ``attacking++; ` `        ``} ` ` `  `        ``// Diagonally to the right down ` `        ``// (row and col simultaneously ` `        ``// increase) ` `        ``row = state[i] + 1, col = i + 1; ` `        ``while` `(col < N && row < N ` `               ``&& board[row][col] != 1) { ` `            ``col++; ` `            ``row++; ` `        ``} ` `        ``if` `(col < N && row < N ` `            ``&& board[row][col] == 1) { ` `            ``attacking++; ` `        ``} ` ` `  `        ``// Diagonally to the left down ` `        ``// (col decreases and row ` `        ``// increases) ` `        ``row = state[i] + 1, col = i - 1; ` `        ``while` `(col >= 0 && row < N ` `               ``&& board[row][col] != 1) { ` `            ``col--; ` `            ``row++; ` `        ``} ` `        ``if` `(col >= 0 && row < N ` `            ``&& board[row][col] == 1) { ` `            ``attacking++; ` `        ``} ` ` `  `        ``// Diagonally to the right up ` `        ``// (col increases and row ` `        ``// decreases) ` `        ``row = state[i] - 1, col = i + 1; ` `        ``while` `(col < N && row >= 0 ` `               ``&& board[row][col] != 1) { ` `            ``col++; ` `            ``row--; ` `        ``} ` `        ``if` `(col < N && row >= 0 ` `            ``&& board[row][col] == 1) { ` `            ``attacking++; ` `        ``} ` `    ``} ` ` `  `    ``// Return pairs. ` `    ``return` `(``int``)(attacking / 2); ` `} ` ` `  `// A utility function that ` `// generates a board configuration ` `// given the state. ` `void` `generateBoard(``int` `board[][N], ` `                   ``int``* state) ` `{ ` ` `  `    ``fill(board, 0); ` `    ``for` `(``int` `i = 0; i < N; i++) { ` `        ``board[state[i]][i] = 1; ` `    ``} ` `} ` ` `  `// A utility function that copies ` `// contents of state2 to state1. ` `void` `copyState(``int``* state1, ``int``* state2) ` `{ ` ` `  `    ``for` `(``int` `i = 0; i < N; i++) { ` `        ``state1[i] = state2[i]; ` `    ``} ` `} ` ` `  `// This function gets the neighbour ` `// of the current state having ` `// the least objective value ` `// amongst all neighbours as ` `// well as the current state. ` `void` `getNeighbour(``int` `board[][N], ` `                  ``int``* state) ` `{ ` `    ``// Declaring and initializing the ` `    ``// optimal board and state with ` `    ``// the current board and the state ` `    ``// as the starting point. ` ` `  `    ``int` `opBoard[N][N]; ` `    ``int` `opState[N]; ` ` `  `    ``copyState(opState, ` `              ``state); ` `    ``generateBoard(opBoard, ` `                  ``opState); ` ` `  `    ``// Initializing the optimal ` `    ``// objective value ` ` `  `    ``int` `opObjective ` `        ``= calculateObjective(opBoard, ` `                             ``opState); ` ` `  `    ``// Declaring and initializing ` `    ``// the temporary board and ` `    ``// state for the purpose ` `    ``// of computation. ` ` `  `    ``int` `NeighbourBoard[N][N]; ` `    ``int` `NeighbourState[N]; ` ` `  `    ``copyState(NeighbourState, ` `              ``state); ` `    ``generateBoard(NeighbourBoard, ` `                  ``NeighbourState); ` ` `  `    ``// Iterating through all ` `    ``// possible neighbours ` `    ``// of the board. ` ` `  `    ``for` `(``int` `i = 0; i < N; i++) { ` `        ``for` `(``int` `j = 0; j < N; j++) { ` ` `  `            ``// Condition for skipping the ` `            ``// current state ` ` `  `            ``if` `(j != state[i]) { ` ` `  `                ``// Initializing temporary ` `                ``// neighbour with the ` `                ``// current neighbour. ` ` `  `                ``NeighbourState[i] = j; ` `                ``NeighbourBoard[NeighbourState[i]][i] ` `                    ``= 1; ` `                ``NeighbourBoard[state[i]][i] ` `                    ``= 0; ` ` `  `                ``// Calculating the objective ` `                ``// value of the neighbour. ` ` `  `                ``int` `temp ` `                    ``= calculateObjective( ` `                        ``NeighbourBoard, ` `                        ``NeighbourState); ` ` `  `                ``// Comparing temporary and optimal ` `                ``// neighbour objectives and if ` `                ``// temporary is less than optimal ` `                ``// then updating accordingly. ` ` `  `                ``if` `(temp <= opObjective) { ` `                    ``opObjective = temp; ` `                    ``copyState(opState, ` `                              ``NeighbourState); ` `                    ``generateBoard(opBoard, ` `                                  ``opState); ` `                ``} ` ` `  `                ``// Going back to the original ` `                ``// configuration for the next ` `                ``// iteration. ` ` `  `                ``NeighbourBoard[NeighbourState[i]][i] ` `                    ``= 0; ` `                ``NeighbourState[i] = state[i]; ` `                ``NeighbourBoard[state[i]][i] = 1; ` `            ``} ` `        ``} ` `    ``} ` ` `  `    ``// Copying the optimal board and ` `    ``// state thus found to the current ` `    ``// board and, state since c++ doesn't ` `    ``// allow returning multiple values. ` ` `  `    ``copyState(state, opState); ` `    ``fill(board, 0); ` `    ``generateBoard(board, state); ` `} ` ` `  `void` `hillClimbing(``int` `board[][N], ` `                  ``int``* state) ` `{ ` ` `  `    ``// Declaring  and initializing the ` `    ``// neighbour board and state with ` `    ``// the current board and the state ` `    ``// as the starting point. ` ` `  `    ``int` `neighbourBoard[N][N] = {}; ` `    ``int` `neighbourState[N]; ` ` `  `    ``copyState(neighbourState, state); ` `    ``generateBoard(neighbourBoard, ` `                  ``neighbourState); ` ` `  `    ``do` `{ ` ` `  `        ``// Copying the neighbour board and ` `        ``// state to the current board and ` `        ``// state, since a neighbour ` `        ``// becomes current after the jump. ` ` `  `        ``copyState(state, neighbourState); ` `        ``generateBoard(board, state); ` ` `  `        ``// Getting the optimal neighbour ` ` `  `        ``getNeighbour(neighbourBoard, ` `                     ``neighbourState); ` ` `  `        ``if` `(compareStates(state, ` `                          ``neighbourState)) { ` ` `  `            ``// If neighbour and current are ` `            ``// equal then no optimal neighbour ` `            ``// exists and therefore output the ` `            ``// result and break the loop. ` ` `  `            ``printBoard(board); ` `            ``break``; ` `        ``} ` `        ``else` `if` `(calculateObjective(board, ` `                                    ``state) ` `                 ``== calculateObjective( ` `                        ``neighbourBoard, ` `                        ``neighbourState)) { ` ` `  `            ``// If neighbour and current are ` `            ``// not equal but their objectives ` `            ``// are equal then we are either ` `            ``// approaching a shoulder or a ` `            ``// local optimum, in any case, ` `            ``// jump to a random neighbour ` `            ``// to escape it. ` ` `  `            ``// Random neighbour ` `            ``neighbourState[``rand``() % N] ` `                ``= ``rand``() % N; ` `            ``generateBoard(neighbourBoard, ` `                          ``neighbourState); ` `        ``} ` ` `  `    ``} ``while` `(``true``); ` `} ` ` `  `// Driver code ` `int` `main() ` `{ ` ` `  `    ``int` `state[N] = {}; ` `    ``int` `board[N][N] = {}; ` ` `  `    ``// Getting a starting point by ` `    ``// randomly configuring the board ` `    ``configureRandomly(board, state); ` ` `  `    ``// Do hill climbing on the ` `    ``// board obtained ` `    ``hillClimbing(board, state); ` ` `  `    ``return` `0; ` `} `

## Python3

 `# Python3 implementation of the ` `# above approach ` `from` `random ``import` `randint ` ` `  `N ``=` `8` ` `  `# A utility function that configures ` `# the 2D array "board" and ` `# array "state" randomly to provide ` `# a starting point for the algorithm. ` `def` `configureRandomly(board, state): ` ` `  `    ``# Iterating through the ` `    ``# column indices ` `    ``for` `i ``in` `range``(N): ` ` `  `        ``# Getting a random row index ` `        ``state[i] ``=` `randint(``0``, ``100000``) ``%` `N; ` ` `  `        ``# Placing a queen on the ` `        ``# obtained place in ` `        ``# chessboard. ` `        ``board[state[i]][i] ``=` `1``; ` `    `  `# A utility function that prints ` `# the 2D array "board". ` `def` `printBoard(board): ` `     `  `    ``for` `i ``in` `range``(N): ` `        ``print``(``*``board[i]) ` ` `  `# A utility function that prints ` `# the array "state". ` `def` `printState( state): ` `    ``print``(``*``state) ` `     `  `# A utility function that compares ` `# two arrays, state1 and state2 and ` `# returns True if equal ` `# and False otherwise. ` `def` `compareStates(state1, state2): ` ` `  ` `  `    ``for` `i ``in` `range``(N): ` `        ``if` `(state1[i] !``=` `state2[i]): ` `            ``return` `False``; ` `     `  `    ``return` `True``; ` ` `  `# A utility function that fills ` `# the 2D array "board" with ` `# values "value" ` `def` `fill(board, value): ` `     `  `    ``for` `i ``in` `range``(N): ` `        ``for` `j ``in` `range``(N): ` `            ``board[i][j] ``=` `value; ` `         `  `# This function calculates the ` `# objective value of the ` `# state(queens attacking each other) ` `# using the board by the ` `# following logic. ` `def` `calculateObjective( board, state): ` ` `  `    ``# For each queen in a column, we check ` `    ``# for other queens falling in the line ` `    ``# of our current queen and if found, ` `    ``# any, then we increment the variable ` `    ``# attacking count. ` ` `  `    ``# Number of queens attacking each other, ` `    ``# initially zero. ` `    ``attacking ``=` `0``; ` ` `  `    ``# Variables to index a particular ` `    ``# row and column on board. ` `    ``for` `i ``in` `range``(N): ` ` `  `        ``# At each column 'i', the queen is ` `        ``# placed at row 'state[i]', by the ` `        ``# definition of our state. ` ` `  `        ``# To the left of same row ` `        ``# (row remains constant ` `        ``# and col decreases) ` `        ``row ``=` `state[i] ` `        ``col ``=` `i ``-` `1``; ` `        ``while` `(col >``=` `0` `and` `board[row][col] !``=` `1``) : ` `            ``col ``-``=` `1` `         `  `        ``if` `(col >``=` `0` `and` `board[row][col] ``=``=` `1``) : ` `            ``attacking ``+``=` `1``; ` `         `  `        ``# To the right of same row ` `        ``# (row remains constant ` `        ``# and col increases) ` `        ``row ``=` `state[i] ` `        ``col ``=` `i ``+` `1``; ` `        ``while` `(col < N ``and` `board[row][col] !``=` `1``): ` `            ``col ``+``=` `1``; ` `         `  `        ``if` `(col < N ``and` `board[row][col] ``=``=` `1``) : ` `            ``attacking ``+``=` `1``; ` `         `  `        ``# Diagonally to the left up ` `        ``# (row and col simultaneously ` `        ``# decrease) ` `        ``row ``=` `state[i] ``-` `1` `        ``col ``=` `i ``-` `1``; ` `        ``while` `(col >``=` `0` `and` `row >``=` `0` `and` `board[row][col] !``=` `1``) : ` `            ``col``-``=` `1``; ` `            ``row``-``=` `1``; ` `         `  `        ``if` `(col >``=` `0` `and` `row >``=` `0`  `and` `board[row][col] ``=``=` `1``) : ` `            ``attacking``+``=` `1``; ` `         `  `        ``# Diagonally to the right down ` `        ``# (row and col simultaneously ` `        ``# increase) ` `        ``row ``=` `state[i] ``+` `1` `        ``col ``=` `i ``+` `1``; ` `        ``while` `(col < N ``and` `row < N  ``and` `board[row][col] !``=` `1``) : ` `            ``col``+``=` `1``; ` `            ``row``+``=` `1``; ` `         `  `        ``if` `(col < N ``and` `row < N ``and` `board[row][col] ``=``=` `1``) : ` `            ``attacking ``+``=` `1``; ` `         `  `        ``# Diagonally to the left down ` `        ``# (col decreases and row ` `        ``# increases) ` `        ``row ``=` `state[i] ``+` `1` `        ``col ``=` `i ``-` `1``; ` `        ``while` `(col >``=` `0` `and` `row < N  ``and` `board[row][col] !``=` `1``) : ` `            ``col ``-``=` `1``; ` `            ``row ``+``=` `1``; ` `         `  `        ``if` `(col >``=` `0` `and` `row < N ``and` `board[row][col] ``=``=` `1``) : ` `            ``attacking ``+``=` `1``; ` `         `  `        ``# Diagonally to the right up ` `        ``# (col increases and row ` `        ``# decreases) ` `        ``row ``=` `state[i] ``-` `1` `        ``col ``=` `i ``+` `1``; ` `        ``while` `(col < N ``and` `row >``=` `0`  `and` `board[row][col] !``=` `1``) : ` `            ``col ``+``=` `1``; ` `            ``row ``-``=` `1``; ` `         `  `        ``if` `(col < N ``and` `row >``=` `0` `and` `board[row][col] ``=``=` `1``) : ` `            ``attacking ``+``=` `1``; ` `         `  `    ``# Return pairs. ` `    ``return` `int``(attacking ``/` `2``); ` ` `  `# A utility function that ` `# generates a board configuration ` `# given the state. ` `def` `generateBoard( board, state): ` `    ``fill(board, ``0``); ` `    ``for` `i ``in` `range``(N): ` `        ``board[state[i]][i] ``=` `1``; ` `     `  `# A utility function that copies ` `# contents of state2 to state1. ` `def` `copyState( state1, state2): ` ` `  `    ``for` `i ``in` `range``(N): ` `        ``state1[i] ``=` `state2[i]; ` `     `  `# This function gets the neighbour ` `# of the current state having ` `# the least objective value ` `# amongst all neighbours as ` `# well as the current state. ` `def` `getNeighbour(board, state): ` ` `  `    ``# Declaring and initializing the ` `    ``# optimal board and state with ` `    ``# the current board and the state ` `    ``# as the starting point. ` `    ``opBoard ``=` `[[``0` `for` `_ ``in` `range``(N)] ``for` `_ ``in` `range``(N)] ` `    ``opState ``=` `[``0` `for` `_ ``in` `range``(N)] ` ` `  `    ``copyState(opState, state); ` `    ``generateBoard(opBoard, opState); ` ` `  `    ``# Initializing the optimal ` `    ``# objective value ` `    ``opObjective  ``=` `calculateObjective(opBoard, opState); ` ` `  `    ``# Declaring and initializing ` `    ``# the temporary board and ` `    ``# state for the purpose ` `    ``# of computation. ` `    ``NeighbourBoard ``=` `[[``0` `for` `_ ``in` `range``(N)] ``for` `_ ``in` `range``(N)] ` `     `  `    ``NeighbourState ``=` `[``0` `for` `_ ``in` `range``(N)] ` `    ``copyState(NeighbourState, state); ` `    ``generateBoard(NeighbourBoard, NeighbourState); ` ` `  `    ``# Iterating through all ` `    ``# possible neighbours ` `    ``# of the board. ` `    ``for` `i ``in` `range``(N): ` `        ``for` `j ``in` `range``(N): ` ` `  `            ``# Condition for skipping the ` `            ``# current state ` `            ``if` `(j !``=` `state[i]) : ` ` `  `                ``# Initializing temporary ` `                ``# neighbour with the ` `                ``# current neighbour. ` `                ``NeighbourState[i] ``=` `j; ` `                ``NeighbourBoard[NeighbourState[i]][i] ``=` `1``; ` `                ``NeighbourBoard[state[i]][i] ``=` `0``; ` ` `  `                ``# Calculating the objective ` `                ``# value of the neighbour. ` `                ``temp ``=` `calculateObjective( NeighbourBoard, NeighbourState); ` ` `  `                ``# Comparing temporary and optimal ` `                ``# neighbour objectives and if ` `                ``# temporary is less than optimal ` `                ``# then updating accordingly. ` ` `  `                ``if` `(temp <``=` `opObjective) : ` `                    ``opObjective ``=` `temp; ` `                    ``copyState(opState, NeighbourState); ` `                    ``generateBoard(opBoard, opState); ` `                 `  `                ``# Going back to the original ` `                ``# configuration for the next ` `                ``# iteration. ` `                ``NeighbourBoard[NeighbourState[i]][i] ``=` `0``; ` `                ``NeighbourState[i] ``=` `state[i]; ` `                ``NeighbourBoard[state[i]][i] ``=` `1``; ` `             `  `    ``# Copying the optimal board and ` `    ``# state thus found to the current ` `    ``# board and, state since c+= 1 doesn't ` `    ``# allow returning multiple values. ` `    ``copyState(state, opState); ` `    ``fill(board, ``0``); ` `    ``generateBoard(board, state); ` ` `  `def` `hillClimbing(board, state): ` ` `  `    ``# Declaring  and initializing the ` `    ``# neighbour board and state with ` `    ``# the current board and the state ` `    ``# as the starting point. ` ` `  `    ``neighbourBoard ``=` `[[``0` `for` `_ ``in` `range``(N)] ``for` `_ ``in` `range``(N) ` `    ``neighbourState ``=` `[``0` `for` `_ ``in` `range``(N)] ` ` `  `    ``copyState(neighbourState, state); ` `    ``generateBoard(neighbourBoard, neighbourState); ` `     `  `    ``while` `True``: ` ` `  `        ``# Copying the neighbour board and ` `        ``# state to the current board and ` `        ``# state, since a neighbour ` `        ``# becomes current after the jump. ` ` `  `        ``copyState(state, neighbourState); ` `        ``generateBoard(board, state); ` ` `  `        ``# Getting the optimal neighbour ` ` `  `        ``getNeighbour(neighbourBoard, neighbourState); ` ` `  `        ``if` `(compareStates(state, neighbourState)) : ` ` `  `            ``# If neighbour and current are ` `            ``# equal then no optimal neighbour ` `            ``# exists and therefore output the ` `            ``# result and break the loop. ` ` `  `            ``printBoard(board); ` `            ``break``; ` `         `  `        ``elif` `(calculateObjective(board, state) ``=``=` `calculateObjective( neighbourBoard,neighbourState)): ` ` `  `            ``# If neighbour and current are ` `            ``# not equal but their objectives ` `            ``# are equal then we are either ` `            ``# approaching a shoulder or a ` `            ``# local optimum, in any case, ` `            ``# jump to a random neighbour ` `            ``# to escape it. ` ` `  `            ``# Random neighbour ` `            ``neighbourState[randint(``0``, ``100000``) ``%` `N]  ``=` `randint(``0``, ``100000``) ``%` `N; ` `            ``generateBoard(neighbourBoard, neighbourState); ` `         `  `# Driver code ` `state ``=` `[``0``] ``*` `N ` `board ``=` `[[``0` `for` `_ ``in` `range``(N)] ``for` `_ ``in` `range``(N)] ` ` `  `# Getting a starting point by ` `# randomly configuring the board ` `configureRandomly(board, state); ` ` `  `# Do hill climbing on the ` `# board obtained ` `hillClimbing(board, state); ` ` `  `# This code is contributed by phasing17. `

## Javascript

 `// JS implementation of the ` `// above approach ` `let  N = 8 ` ` `  `// A utility function that configures ` `// the 2D array "board" and ` `// array "state" randomly to provide ` `// a starting point for the algorithm. ` `function` `configureRandomly(board, state) ` `{ ` ` `  `    ``// Iterating through the ` `    ``// column indices ` `    ``for` `(``var` `i = 0; i < N; i++) { ` ` `  `        ``// Getting a random row index ` `        ``state[i] = Math.floor(Math.random() * 100000) % N; ` ` `  `        ``// Placing a queen on the ` `        ``// obtained place in ` `        ``// chessboard. ` `        ``board[state[i]][i] = 1; ` `    ``} ` `} ` ` `  `// A utility function that prints ` `// the 2D array "board". ` `function` `printBoard(board) ` `{ ` ` `  `    ``for` `(``var` `i = 0; i < N; i++) { ` `        ``process.stdout.write(``" "``); ` `        ``for` `(``var` `j = 0; j < N; j++) { ` `            ``process.stdout.write(board[i][j] + ``" "``); ` `        ``} ` `        ``process.stdout.write(``"\n"``); ` `    ``} ` `} ` ` `  `// A utility function that prints ` `// the array "state". ` `function` `printState( state) ` `{ ` ` `  `    ``for` `(``var` `i = 0; i < N; i++) { ` `       ``process.stdout.write(``" "` `+ state[i] + ``" "``); ` `    ``} ` `    ``process.stdout.write(``"\n"``); ` `} ` ` `  `// A utility function that compares ` `// two arrays, state1 and state2 and ` `// returns true if equal ` `// and false otherwise. ` `function` `compareStates(state1, ` `                   ``state2) ` `{ ` ` `  `    ``for` `(``var` `i = 0; i < N; i++) { ` `        ``if` `(state1[i] != state2[i]) { ` `            ``return` `false``; ` `        ``} ` `    ``} ` `    ``return` `true``; ` `} ` ` `  `// A utility function that fills ` `// the 2D array "board" with ` `// values "value" ` `function` `fill(board, value) ` `{ ` `    ``for` `(``var` `i = 0; i < N; i++) { ` `        ``for` `(``var` `j = 0; j < N; j++) { ` `            ``board[i][j] = value; ` `        ``} ` `    ``} ` `} ` ` `  `// This function calculates the ` `// objective value of the ` `// state(queens attacking each other) ` `// using the board by the ` `// following logic. ` `function` `calculateObjective( board, ` `                        ``state) ` `{ ` ` `  `    ``// For each queen in a column, we check ` `    ``// for other queens falling in the line ` `    ``// of our current queen and if found, ` `    ``// any, then we increment the variable ` `    ``// attacking count. ` ` `  `    ``// Number of queens attacking each other, ` `    ``// initially zero. ` `    ``var` `attacking = 0; ` ` `  `    ``// Variables to index a particular ` `    ``// row and column on board. ` `    ``var` `row, col; ` ` `  `    ``for` `(``var` `i = 0; i < N; i++) { ` ` `  `        ``// At each column 'i', the queen is ` `        ``// placed at row 'state[i]', by the ` `        ``// definition of our state. ` ` `  `        ``// To the left of same row ` `        ``// (row remains constant ` `        ``// and col decreases) ` `        ``row = state[i], col = i - 1; ` `        ``while` `(col >= 0 ` `               ``&& board[row][col] != 1) { ` `            ``col--; ` `        ``} ` `        ``if` `(col >= 0 ` `            ``&& board[row][col] == 1) { ` `            ``attacking++; ` `        ``} ` ` `  `        ``// To the right of same row ` `        ``// (row remains constant ` `        ``// and col increases) ` `        ``row = state[i], col = i + 1; ` `        ``while` `(col < N ` `               ``&& board[row][col] != 1) { ` `            ``col++; ` `        ``} ` `        ``if` `(col < N ` `            ``&& board[row][col] == 1) { ` `            ``attacking++; ` `        ``} ` ` `  `        ``// Diagonally to the left up ` `        ``// (row and col simultaneously ` `        ``// decrease) ` `        ``row = state[i] - 1, col = i - 1; ` `        ``while` `(col >= 0 && row >= 0 ` `               ``&& board[row][col] != 1) { ` `            ``col--; ` `            ``row--; ` `        ``} ` `        ``if` `(col >= 0 && row >= 0 ` `            ``&& board[row][col] == 1) { ` `            ``attacking++; ` `        ``} ` ` `  `        ``// Diagonally to the right down ` `        ``// (row and col simultaneously ` `        ``// increase) ` `        ``row = state[i] + 1, col = i + 1; ` `        ``while` `(col < N && row < N ` `               ``&& board[row][col] != 1) { ` `            ``col++; ` `            ``row++; ` `        ``} ` `        ``if` `(col < N && row < N ` `            ``&& board[row][col] == 1) { ` `            ``attacking++; ` `        ``} ` ` `  `        ``// Diagonally to the left down ` `        ``// (col decreases and row ` `        ``// increases) ` `        ``row = state[i] + 1, col = i - 1; ` `        ``while` `(col >= 0 && row < N ` `               ``&& board[row][col] != 1) { ` `            ``col--; ` `            ``row++; ` `        ``} ` `        ``if` `(col >= 0 && row < N ` `            ``&& board[row][col] == 1) { ` `            ``attacking++; ` `        ``} ` ` `  `        ``// Diagonally to the right up ` `        ``// (col increases and row ` `        ``// decreases) ` `        ``row = state[i] - 1, col = i + 1; ` `        ``while` `(col < N && row >= 0 ` `               ``&& board[row][col] != 1) { ` `            ``col++; ` `            ``row--; ` `        ``} ` `        ``if` `(col < N && row >= 0 ` `            ``&& board[row][col] == 1) { ` `            ``attacking++; ` `        ``} ` `    ``} ` ` `  `    ``// Return pairs. ` `    ``return` `Math.floor(attacking / 2); ` `} ` ` `  `// A utility function that ` `// generates a board configuration ` `// given the state. ` `function` `generateBoard( board, ` `                   ``state) ` `{ ` ` `  `    ``fill(board, 0); ` `    ``for` `(``var` `i = 0; i < N; i++) { ` `        ``board[state[i]][i] = 1; ` `    ``} ` `} ` ` `  `// A utility function that copies ` `// contents of state2 to state1. ` `function` `copyState( state1, state2) ` `{ ` ` `  `    ``for` `(``var` `i = 0; i < N; i++) { ` `        ``state1[i] = state2[i]; ` `    ``} ` `} ` ` `  `// This function gets the neighbour ` `// of the current state having ` `// the least objective value ` `// amongst all neighbours as ` `// well as the current state. ` `function` `getNeighbour(board, ` `                  ``state) ` `{ ` `    ``// Declaring and initializing the ` `    ``// optimal board and state with ` `    ``// the current board and the state ` `    ``// as the starting point. ` ` `  `    ``var` `opBoard = ``new` `Array(N); ` `    ``for` `(``var` `i = 0; i < N; i++) ` `        ``opBoard[i] = ``new` `Array(N).fill(0); ` `    ``var` `opState = ``new` `Array(N).fill(0); ` ` `  `    ``copyState(opState, ` `              ``state); ` `    ``generateBoard(opBoard, ` `                  ``opState); ` ` `  `    ``// Initializing the optimal ` `    ``// objective value ` ` `  `    ``var` `opObjective  = calculateObjective(opBoard, ` `                             ``opState); ` ` `  `    ``// Declaring and initializing ` `    ``// the temporary board and ` `    ``// state for the purpose ` `    ``// of computation. ` ` `  `    ``var` `NeighbourBoard = ``new` `Array(N).fill(``new` `Array(N).fill(0)); ` `    ``var` `NeighbourState = ``new` `Array(N).fill(0); ` `    ``copyState(NeighbourState, ` `              ``state); ` `    ``generateBoard(NeighbourBoard, ` `                  ``NeighbourState); ` ` `  `    ``// Iterating through all ` `    ``// possible neighbours ` `    ``// of the board. ` ` `  `    ``for` `(``var` `i = 0; i < N; i++) { ` `        ``for` `(``var` `j = 0; j < N; j++) { ` ` `  `            ``// Condition for skipping the ` `            ``// current state ` ` `  `            ``if` `(j != state[i]) { ` ` `  `                ``// Initializing temporary ` `                ``// neighbour with the ` `                ``// current neighbour. ` ` `  `                ``NeighbourState[i] = j; ` `                ``NeighbourBoard[NeighbourState[i]][i] ` `                    ``= 1; ` `                ``NeighbourBoard[state[i]][i] ` `                    ``= 0; ` ` `  `                ``// Calculating the objective ` `                ``// value of the neighbour. ` ` `  `                ``var` `temp ` `                    ``= calculateObjective( ` `                        ``NeighbourBoard, ` `                        ``NeighbourState); ` ` `  `                ``// Comparing temporary and optimal ` `                ``// neighbour objectives and if ` `                ``// temporary is less than optimal ` `                ``// then updating accordingly. ` ` `  `                ``if` `(temp <= opObjective) { ` `                    ``opObjective = temp; ` `                    ``copyState(opState, ` `                              ``NeighbourState); ` `                    ``generateBoard(opBoard, ` `                                  ``opState); ` `                ``} ` ` `  `                ``// Going back to the original ` `                ``// configuration for the next ` `                ``// iteration. ` ` `  `                ``NeighbourBoard[NeighbourState[i]][i] ` `                    ``= 0; ` `                ``NeighbourState[i] = state[i]; ` `                ``NeighbourBoard[state[i]][i] = 1; ` `            ``} ` `        ``} ` `    ``} ` ` `  `    ``// Copying the optimal board and ` `    ``// state thus found to the current ` `    ``// board and, state since c++ doesn't ` `    ``// allow returning multiple values. ` ` `  `    ``copyState(state, opState); ` `    ``fill(board, 0); ` `    ``generateBoard(board, state); ` `} ` ` `  `function` `hillClimbing(board, state) ` `{ ` ` `  `    ``// Declaring  and initializing the ` `    ``// neighbour board and state with ` `    ``// the current board and the state ` `    ``// as the starting point. ` ` `  `    ``var` `neighbourBoard = ``new` `Array(N); ` `    ``for` `(``var` `i = 0; i < N; i++) ` `        ``neighbourBoard[i] = ``new` `Array(N).fill(0); ` `    ``var` `neighbourState = ``new` `Array(N).fill(0) ` ` `  `    ``copyState(neighbourState, state); ` `    ``generateBoard(neighbourBoard, ` `                  ``neighbourState); ` ` `  `    ``do` `{ ` ` `  `        ``// Copying the neighbour board and ` `        ``// state to the current board and ` `        ``// state, since a neighbour ` `        ``// becomes current after the jump. ` ` `  `        ``copyState(state, neighbourState); ` `        ``generateBoard(board, state); ` ` `  `        ``// Getting the optimal neighbour ` ` `  `        ``getNeighbour(neighbourBoard, ` `                     ``neighbourState); ` ` `  `        ``if` `(compareStates(state, ` `                          ``neighbourState)) { ` ` `  `            ``// If neighbour and current are ` `            ``// equal then no optimal neighbour ` `            ``// exists and therefore output the ` `            ``// result and break the loop. ` ` `  `            ``printBoard(board); ` `            ``break``; ` `        ``} ` `        ``else` `if` `(calculateObjective(board, ` `                                    ``state) ` `                 ``== calculateObjective( ` `                        ``neighbourBoard, ` `                        ``neighbourState)) { ` ` `  `            ``// If neighbour and current are ` `            ``// not equal but their objectives ` `            ``// are equal then we are either ` `            ``// approaching a shoulder or a ` `            ``// local optimum, in any case, ` `            ``// jump to a random neighbour ` `            ``// to escape it. ` ` `  `            ``// Random neighbour ` `            ``neighbourState[(Math.floor(Math.random() * 100000) % N)] ` `                ``= Math.floor(Math.random() * 100000) % N; ` `            ``generateBoard(neighbourBoard, ` `                          ``neighbourState); ` `        ``} ` ` `  `    ``} ``while` `(``true``); ` `} ` ` `  `// Driver code ` `var` `state = ``new` `Array(N).fill(0); ` `var` `board =  ``new` `Array(N); ` `for` `(``var` `i = 0; i < N; i++) ` `        ``board[i] = ``new` `Array(N).fill(0); ` ` `  `    ``// Getting a starting point by ` `    ``// randomly configuring the board ` `    ``configureRandomly(board, state); ` ` `  `    ``// Do hill climbing on the ` `    ``// board obtained ` `    ``hillClimbing(board, state); ` ` `  `// This code is contributed by phasing17. `

Output:

``` 0 0 1 0 0 0 0 0
0 0 0 0 0 1 0 0
0 0 0 0 0 0 0 1
1 0 0 0 0 0 0 0
0 0 0 1 0 0 0 0
0 0 0 0 0 0 1 0
0 0 0 0 1 0 0 0
0 1 0 0 0 0 0 0```

Complexity Analysis

• The time complexity for this algorithm can be divided into three parts:
1. Calculating Objective – The calculation of objective involves iterating through all queens on board and checking the no. of attacking queens, which is done by our calculateObjective function in O(N2) time.

2. Neighbour Selection and Number of neighbours – The description of neighbours in our problem gives a total of N(N-1) neighbours for the current state. The selection procedure is best fit and therefore requires iterating through all neighbours, which is again O(N2)

3. Search Space –  Search space of our problem consists of a total of  NN states, corresponding to all possible configurations of the N Queens on board. Note that this is after taking into account the additional constraint of one queen per column.

• Therefore, the worst-case time complexity of our algorithm is O(NN). But, this worst-case occurs rarely in practice and thus we can safely consider it to be as good as any other algorithm there is for the N Queen problem. Hence, the effective time complexity consists of only calculating the objective for all neighbours up to a certain depth(no of jumps the search makes), which does not depend on N. Therefore, if the depth of search is d then the time complexity is O(N2 * N2  * d), which is O(d*N4).

My Personal Notes arrow_drop_up
Related Articles