I am currently studying the beautiful topic of recursive backtracking.
I’ve already tried classical examples like finding the shortest path out of a maze, or the n-queens problem. But the problem I’m working on right now really keeps me confused:
Actually I thought it might be an easy exercise to solve a simple jigsaw-puzzle:
I have a board with the size of n = a * b and exactly that much (n) pieces.
In the end I want to have all the pieces to be put on the board in a certain order where they obey certain restrictions (like matching their neighbours). Fairly easy, I thought and I came up with the following algorithm:
public board recursiveSolve(Board board, Piece[] pieces, int position){
// base case
if(position == board.getLength())
return board;
else{
// For each possible piece
for(int i = 0; i < pieces.length; i++){
// if the piece is placeable at that position
// place it and search on recursively
if(board.isValid(piece[i], position)){
board.putPiece(pieces[i], position);
// THIS IS THE FISHY PART!!
// Now I need to pass a set of pieces to the function recursively
// that does not contain the current one (pieces[i])
// But I fear my (following) approach is too heap-intensive
Piece[] subPieces = new Piece[pieces.length - 1];
// fill subPieces with all elements from pieces except from the one
// at position i
for (int j = 0; j < subPieces.length; j++) {
if(j >= i)
subPieces[j] = pieces[j+1];
else
subPieces[j] = pieces[j];
}
if(recursiveSolve(board, subPieces, position + 1) != null)
return board;
else
board.removePiece(position);
}
}
// If this is reached, none of the pieces have worked -> go back
return null;
}
Well basically, this algorithm does what it should do – but unfortunately it only works for “small” board sizes (n < 100).
Because if I have a board like 10 x 10 squares and 100 pieces, the function searches and searches and just doesn’t come to an end until JVM crashes due to insufficient heap space.
I even tried setting eclipse’s memory size limit up to 1.2g which made the function work longer but still was not enough.
So my question is: Is it possible to optimize the algorithm above to make it work for board sizes n > 100? What am I doing wrong? Or am I taking the entirely wrong approach?
Thank your very much for you help in advance.
It seems the main heap usage in your program is indeed where you suspect: when initializing the new array of
size pieces.length -1.Note that you can indeed save a lot of space here! since you actually use only the ‘deepest’ set.
If you still want to use an array, you might want to pass an extra parameter:
start, and implementswap(arr,i,k)which swaps the i’th and k’th elements in arr, and in each step, instead of allocating a new array,swap(pieces,start,i), and pass to the new functionstart+1in the recursive step. note that since you always swap the last element, the next steps do no care of the swaps, becasue they are after thestartposition of the array. So basically, because the algorithm never ‘looks back’, you don’t have any problems swapping these elements around…Should look something like that:
You are probably aware that backtracking algorithms are time-consuming [exponential!], so even with space-optimized version, the algorithm might run for a very long time until an answer is found.