An Efficient Algorithm for the Knight's Tour Problem Chessboard
http://community.topcoder.com/stat?c=problem_statement&pm=3509&rd=6528
Given the size of the chess board and initial position of the knight, what is the probability that after k moves the knight will be inside the chess board.
Note:-
1) The knight makes its all 8 possible moves with equal probability.
2) Once the knight is outside the chess board it cannot come back inside.
https://www.quora.com/Given-the-position-x-y-of-a-knight-on-an-8X8-chess-board-what-is-the-probability-that-it-stays-within-the-chess-board-after-n-moves
Base cases:
There are 2 possible base cases:
∑8i=1 ( FindProbability(next_x, next_y, step-1) ) / 8.0
where next_x, next_y are the possible next positions of the knight at position (x,y).
Memoization:
There are a lot of overlapping computations in the above recursion. There might be numerous calls to the function
with the same parameters. In order to prevent recomputing these values again and again, we can simply cache the computed values every time we find them and just return this value for subsequent function calls with the same parameters.
For this, a 3D array
is maintained, and the computed values are stored in the array.
Algorithm:
Start with the initial coordinates of the knight. Make all possible moves for this position and multiply these moves with their probability, for each move recursively call the function continue this process till the terminating condition is met. Terminating condition is if the knight is outside the chess board, in this case return 0, or the desired number of moves is exhausted, in this case return 1.
As we can see that the current state of the recursion is dependent only on the current coordinates and number of steps done so far. Therefore we can memoize this information in a tabular form.
http://community.topcoder.com/tc?module=Static&d1=match_editorials&d2=tccc05_online_rd_1#3509
https://code.google.com/p/my-topcoder-code/source/browse/Code/src/tccc2005_round_1/ChessKnight.java
Read full article from An Efficient Algorithm for the Knight's Tour Problem Chessboard
http://community.topcoder.com/stat?c=problem_statement&pm=3509&rd=6528
Given the size of the chess board and initial position of the knight, what is the probability that after k moves the knight will be inside the chess board.
Note:-
1) The knight makes its all 8 possible moves with equal probability.
2) Once the knight is outside the chess board it cannot come back inside.
https://www.quora.com/Given-the-position-x-y-of-a-knight-on-an-8X8-chess-board-what-is-the-probability-that-it-stays-within-the-chess-board-after-n-moves
Base cases:
There are 2 possible base cases:
- If the position (x,y) is outside the board, then the probability that it is within the board is 0. So we just
return 0;
- If step == 0, then we have no more moves left. In this case if the passed parameter (x,y) is within the board, then we
return 1;
where next_x, next_y are the possible next positions of the knight at position (x,y).
Memoization:
There are a lot of overlapping computations in the above recursion. There might be numerous calls to the function
FindProbability
For this, a 3D array
double
memo
[
8
][
8
][
MAX_MOVES
]
Algorithm:
Start with the initial coordinates of the knight. Make all possible moves for this position and multiply these moves with their probability, for each move recursively call the function continue this process till the terminating condition is met. Terminating condition is if the knight is outside the chess board, in this case return 0, or the desired number of moves is exhausted, in this case return 1.
As we can see that the current state of the recursion is dependent only on the current coordinates and number of steps done so far. Therefore we can memoize this information in a tabular form.
Expected time complexity:
O((n ^ 2) * k) where n is the size of the board and k is the number of moves.
O((n ^ 2) * k) where n is the size of the board and k is the number of moves.
Expected space complexity:
O((n ^ 2) * k) where n is the size of the board and k is the number of moves.
O((n ^ 2) * k) where n is the size of the board and k is the number of moves.
#define MAXSIZE 100 |
#define MAXK 100 |
double dp[MAXSIZE][MAXSIZE][MAXK]; |
int vis[MAXSIZE][MAXSIZE][MAXK]; //stores 1 if there is a corresponding dp entry, 0 otherwise |
double prob_knight( int x, int y, int size, int step, int k) |
{ |
//if knight is outside the board |
if (x < 0 || y < 0 || x >= size || y >= size) return 0; |
//if all moves are exhausted |
if (step == k) return 1; |
//if dp table has the this value stored return it |
if (vis[x][y][k] != 0) |
return dp[x][y][k]; |
vis[x][y][step] = 1; |
//all possible x direction's for knight to move |
int dirx[] = {2, 2, -2, -2, 1, 1, -1, -1}; |
//corresponding y direction for knight |
int diry[] = {1, -1, 1, -1, 2, -2, 2, -2}; |
double ans = 0; |
for ( int i = 0;i < 8; ++i){ |
//knight makes the next move with probability (1 / 8) |
ans = ans + (( double )1 / ( double )8) * prob_knight(x + dirx[i], y + diry[i], size, step + 1, k); |
} |
//update the dp table |
dp[x][y][k] = ans; |
return ans; |
} |
The idea is to keep track for each number of moves the probability that the knight will be on a certain square. Initially the probability is 1 (100%) that it will be on the start square and 0 on all other squares. After one move, the probability is 0.125 that it will be on any of the eight squares a knight distance away from the start, and 0 on all the other squares. If any of these 8 squares is outside the board, it's simply ignored - it doesn't affect the probability for any of the other squares.
Generally, the probability that the knight will be on a certain square after n moves is the sum of the probabilities of it being on the 8 squares a knight distance away after n - 1 moves, divided by 8 (this is basic probability math). By first determining the probability of the knight being on all 64 squares after 1 move, then 2 moves etc, we get an efficient algorithm:
for(int i=1; i<=n; i++) // n = number of moves we want the answer for for(int x=0; x<8; x++) for(int y=0; y<8; y++) { double prob = 0.0; for(int d=0; d<8; d++) { if (x+dx[d] >= 0 && x+dx[d] < 8 && y+dy[d] >= 0 && y+dy[d] < 8) prob += boardprob[i-1][y+dy[d]][x+dx[d]] / 8.0; } boardprob[i][y][x] = prob; }
The answer is then simply the sum of the knight being on the 64 squares after n moves.
https://github.com/livingstonese/topcoder/blob/master/src/main/java/tccc05/round1/ChessKnight.javapublic class ChessKnight { private static final int MAX_N = 101; | |
private static final int MAX_DIM = 9; | |
double[][][] dp = new double[MAX_N][MAX_DIM][MAX_DIM]; | |
public double probability(int x, int y, int n) { | |
for (int i = 0; i < MAX_DIM; i++) { | |
Arrays.fill(dp[0][i], 1.0); | |
} | |
int[] dx = {-2, -2, -1, -1, 1, 1, 2, 2}; | |
int[] dy = {1, -1, 2, -2, 2, -2, 1, -1}; | |
for (int curN = 1; curN <= n; curN++) { | |
for (int curX = 1; curX < MAX_DIM; curX++) { | |
for (int curY = 1; curY < MAX_DIM; curY++) { | |
double prob = 0; | |
for (int i = 0; i < dx.length; i++) { | |
int nextX = curX + dx[i]; | |
int nextY = curY + dy[i]; | |
if (nextX > 0 && nextX < MAX_DIM && nextY > 0 && nextY < MAX_DIM) | |
prob += (0.125 * dp[curN-1][nextX][nextY]); | |
} | |
dp[curN][curX][curY] = prob; | |
} | |
} | |
} | |
return dp[n][x][y]; | |
} | |
} |
public double probability(int x, int y, int n){ |
double chess[][][]=new double[8][8][n+1]; |
x--; |
y--; |
chess[x][y][0]=1; |
int move[][]={{2,1},{2,-1},{-2,1},{-2,-1},{1,2},{1,-2},{-1,2},{-1,-2}}; |
for(int i=0;i<n;++i){ |
for(int xx=0;xx<8;++xx){ |
for(int yy=0;yy<8;++yy){ |
if(chess[xx][yy][i]!=0){ |
for(int k=0;k<8;++k){ |
int curx=xx+move[k][0]; |
int cury=yy+move[k][1]; |
if(curx>=0&&curx<8&&cury>=0&&cury<8){ |
chess[curx][cury][i+1]+=chess[xx][yy][i]/8; |
} |
} |
} |
} |
} |
} |
double result=0; |
for(int xx=0;xx<8;++xx){ |
for(int yy=0;yy<8;++yy){ |
result+=chess[xx][yy][n]; |
} |
} |
return result; |
} |