Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

When is recursive backtracking appropriate?

I'm making a SudokuSolver for a class, and I'm having trouble with the solve method. My current solution uses recursive backtracking (I think).

Assignment Requirements

int solve() -- tries to solve the puzzle using the strategy described above. Returns the number of solutions.

(The strategy described above)

When assigning a number to a spot, never assign a number that, at that moment, conflicts with the spot's row, column, or square. We are up-front careful about assigning legal numbers to a spot, rather than assigning any number 1..9 and finding the problem later in the recursion. Assume that the initial grid is all legal, and make only legal spot assignments thereafter.

Pseudocode Idea

I can follow this iteratively for a small input. For example, say I have to unsolved cells Cell #1 and Cell #2. #1 has possibilities { 1, 3 } and #2 has possibilities { 2, 3 }. I would then

set 1 to 1
    set 2 to 2
        hasConflicts? 0 : 1
    set 2 to 3
        hasConflicts? 0 : 1
set 1 to 3
    set 2 to 2
        hasConflicts? 0 : 1
    set 2 to 3
        hasConflicts? 0 : 1

Actual Code

public int solve() {
    long startTime = System.currentTimeMillis();
    int result = 0;

    if (!hasConflicts()) {
        Queue<VariableCell> unsolved = getUnsolved();
        reduceUnsolvedPossibilities(unsolved);  // Gets the possibilities down from all of 1-9

        if (!hasConflicts()) {
            result = solveRec(unsolved);
        }
    }

    mElapsedTime = System.currentTimeMillis() - startTime;
    return result;
}

protected int solveRec(Queue<VariableCell> unsolved) {
    if (unsolved.isEmpty()) {
        return (hasConflicts()) ? 0 : 1;
    }

    int result = 0;
    VariableCell cell = unsolved.remove();
    Iterator<String> possibilityIt = cell.getPossibilities().iterator();

    while (possibilityIt.hasNext()) {
        cell.setSymbol(possibilityIt.next());

        if (hasConflicts()) {
            possibilityIt.remove();
        } else {
            ++result;
        }
    }

    return result + solveRec(unsolved);
}

Test Results

testSolveSingleSolution
    expected 1, actual 1

testSolveSolved
    expected 1, actual 1

testSolveUnsolvable
    expected 0, actual 0

testSolveMultiSolutions
    expected 2, actual 7  // MAJOR PROBLEM!

Some Good Explanations of Recursive Backtracking

  • This answer to StackOverflow - Recursive solution to Sudoku generator
  • This answer to StackOverflow - BackTracking in a maze
  • This answer to StackOverflow - Backtracking algorithm for prime sequence
  • This answer to StackOverflow - How to find the first solution only with this backtracking
  • The Wikipedia article on Backtracking
  • Recursive Backtracking Explanation

Question

I've done recursive backtracking before, I've looked at all those links above and more, and I'm still having trouble. I think the problem lies in my thinking about how to solve this. (See Pseudocode Idea.) Is it appropriate to use recursive backtracking for an exhaustive search? Is the backtracking right but the implementation wrong? Is there a better algorithm I can use than recursive backtracking?

like image 553
Eva Avatar asked Apr 12 '26 01:04

Eva


1 Answers

This looks like an implementation problem. Check the block where you're incrementing result. Do you really want to increment for each valid value of that cell? And for that matter overwrite the older valid value if there are several that are valid?

like image 89
Thomas Avatar answered Apr 13 '26 15:04

Thomas



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!