2012-07-17 19 views
10

Robię SudokuSolver dla klasy i mam problem z metodą rozwiązania. Moje obecne rozwiązanie wykorzystuje rekursywny backtracking (chyba).Kiedy rekursywne kopiowanie jest odpowiednie?

przypisania Wymagania

int solve() - stara się rozwiązać zagadkę przy pomocy strategii opisanej powyżej. Zwraca liczbę rozwiązań.

(Strategia opisana powyżej)

Podczas przypisywania numeru do miejsca, nigdy przypisać numer, że w tej chwili, konflikty z rzędu rzutu za, kolumny lub kwadratu. Dokładamy starań, aby przypisać numery prawne do miejsca, a nie przypisywać numer 1..9 i znaleźć problem później w rekursji. Załóżmy, że początkowa siatka jest legalna i od tego czasu wykonujesz tylko legalne zlecenia dodatkowe.

Pseudokod Idea

mogę śledzić to iteracyjnie dla małego wejścia. Na przykład powiedzmy, że mam nierozwiązane komórki Nr komórki 1 i Nr komórki 2. # 1 ma możliwości {1, 3}, a # 2 ma możliwości {2, 3}. Chciałbym następnie

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 

rzeczywisty kod

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); 
} 

Wyniki testu

testSolveSingleSolution 
    expected 1, actual 1 

testSolveSolved 
    expected 1, actual 1 

testSolveUnsolvable 
    expected 0, actual 0 

testSolveMultiSolutions 
    expected 2, actual 7 // MAJOR PROBLEM! 

jakiś dobry Objaśnienia rekurencyjnych Backtracking

Pytanie

Przedtem robiłem rekursję wstecz, sprawdziłem wszystkie powyższe linki powyżej i więcej, i nadal mam problemy. Myślę, że problem leży w moim rozmyślaniu o tym, jak rozwiązać ten problem. (Patrz Pseudocode Idea.) Czy należy stosować rekursywne wycofywanie w celu wyczerpującego wyszukiwania? Czy poprawne jest cofnięcie, ale implementacja jest nieprawidłowa? Czy istnieje lepszy algorytm, którego mogę użyć, niż rekursywne wycofywanie?

+0

Wycofanie to rozsądne podejście, jeśli możesz przyciąć wyszukiwanie. – nikhil

+0

@nikhil Czy przycinanie musi nastąpić podczas rekursji? – Eva

+1

Jest to integralna część, ale jedyną rzeczą, którą robi, jest pomoc w osiągach (i po prostu musisz przeszukać całe drzewo w najgorszym przypadku, aby znaleźć właściwe rozwiązanie, w przeciwieństwie do gier przeciwnika, w których niekoniecznie potrzebujesz "najlepszego" "możliwy ruch, tylko najlepszy ruch jaki możesz znaleźć w danej szczelinie czasowej). Tylko zezwolenie na prawidłowe ruchy jest już rodzajem przycinania. W każdym razie, jeśli otrzymasz zły wynik, to nie jest powód (z wyjątkiem sytuacji, gdy masz błąd). [Możliwe algorytmy do rozwiązania] (http://en.wikipedia.org/wiki/Algorithmics_of_sudoku). – Voo

Odpowiedz

0

To wygląda na problem z implementacją. Sprawdź blok, w którym zwiększasz wynik. Czy na pewno chcesz inkrementować każdą prawidłową wartość tej komórki? I w tym przypadku zastąpić starszą prawidłową wartość, jeśli jest kilka ważnych?

+0

Widzę, co masz na myśli mówiąc o zwiększaniu wartości. Podwyższa się zbytnio i to powinno być zrobione tylko po znalezieniu prawidłowego rozwiązania. Nie jestem pewien, co masz na myśli, nie zastępując starszej wartości. Próbuję sprawdzić poprawne rozwiązanie z tą wartością przed przejściem do następnej wartości. Wydaje mi się, że mogę też źle wykonać tę część. – Eva

+0

Przyjrzyj się uważnie pętli 'while (potentialIt.hasNext())', zwracając szczególną uwagę na miejsce ustawienia symbolu w porównaniu do miejsca, gdzie wykonywane jest rekurencyjne wywołanie 'solveRec'. – Thomas