2013-06-22 1 views
-1

나는 스도쿠 퍼즐을 만드는 프로그램을 만들고있다. 이 작업을 수행하기 위해 역 추적 알고리즘을 사용하려고했지만 프로그램이 작동하지 않습니다. 이 프로그램은 무한히 실행되고 결코 해결책을 반환하지 않습니다. 나는 그저 사소한 문제인지 또는 백 트랙킹 알고리즘을 작성하는 방법을 오해하는지 잘 모른다.역 추적 알고리즘의 문제점은 무엇입니까?

package sudoku; 

import java.util.Random; 

public class Puzzle { 

    // 9x9 puzzle 
    private int puzzle[][] = new int[9][9]; 

    // generate a completely solved sudoku board 
    public int[][] generate() { 

     Random gen = new Random(); 

     // add each number to the board square by square 
     for (int y = 0; y < 9; y++) { 
      for (int x = 0; x < 9; x++) { 

       // generate random number 1-9 
       int num = gen.nextInt(9) + 1; 

       int count = 0; 
       boolean valid = false; 

       while (valid == false) { 

        // check if number is valid 
        if (checkRow(num, x) && checkCol(num, y) 
          && checkSection(num, x, y)) { 

         // add number to the board 
         puzzle[x][y] = num; 

         // exit loop, move on to next square 
         valid = true; 

        } else { 

         // try next number 
         if (num == 9) { 
          num = 1; 
         } else { 
          num++; 
         } 

         // increase counter. 
         count++; 

         // if counter reached 9, then all numbers were tried and 
         // none were valid, begin backtracking 
         if (count == 9) { 

          // go back 1 square 
          if (x == 0) { 
           x = 8; 
           y--; 
          } else { 
           x--; 
          } 

          // empty square 
          puzzle[x][y] = 0; 

          //reset count 
          count = 0; 

         } 

        } 

       } 
      } 
     } 

     return puzzle; 
    } 

    // check each element of the row for num, if num is found return false 
    private boolean checkRow(int num, int row) { 

     for (int i = 0; i < 9; i++) { 
      if (puzzle[row][i] == num) { 
       return false; 
      } 
     } 

     return true; 
    } 

    // check each element of the column for num, if num is found return false 
    private boolean checkCol(int num, int col) { 

     for (int i = 0; i < 9; i++) { 
      if (puzzle[i][col] == num) { 
       return false; 
      } 
     } 

     return true; 
    } 

    // check each element of the section for num, if num is found return false 
    private boolean checkSection(int num, int xPos, int yPos) { 

     int[][] section = new int[3][3]; 
     section = getSection(xPos, yPos); 

     for (int i = 0; i < 3; i++) { 
      for (int j = 0; j < 3; j++) { 
       if (section[i][j] == num) 
        return false; 
      } 
     } 
     return true; 

    } 

    // return the 3x3 section the given coordinates are in 
    private int[][] getSection(int xPos, int yPos) { 

     int[][] section = new int[3][3]; 
     int xIndex = 3 * (xPos/3); 
     int yIndex = 3 * (yPos/3); 

     for (int i = 0; i < 3; i++) { 
      for (int j = 0; j < 3; j++) { 
       section[i][j] = puzzle[xIndex + i][yIndex + j]; 
      } 
     } 

     return section; 

    } 
} 
+3

프로그램을 작성하는 데 무엇을 사용합니까? NetBeans 또는 Eclipse와 같은 텍스트 편집기 또는 IDE를 사용하고 있습니까? 나중에 디버거를 사용하는 방법을 배워야합니다. 이것은 모든 프로그래머에게 필수적인 도구입니다. –

+0

이전에 재귀가없는 역 추적을 한 번도 해보지 않았습니다. 지금 내가 왜 그런지 알 것 같아. 프로그램 실행을 통해 추적을 시작하십시오. 작은 보드부터 시작하십시오. –

+1

루프의 중간에서'for'의 인덱스를 변경하지 마십시오. 이것은 컴파일러가 코드를 최적화하지 못하게하는 나쁜 습관입니다. – SJuan76

답변

1

여러 가지 문제가 발생할 수 있습니다. 나는 단지 예를 든다.

역 추적이 작동하지 않는 주된 이유는 역 추적을 수행하지 않기 때문입니다. 트리에서 하나의 상태로 돌아가고, 역 추적은 하위 트리의 모든 가능성을 검사 한 다음 (아무도 유효하지 않은 경우) 그 하위 트리가 아무리 높다하더라도 그 하위 트리를 무시한다는 것을 의미합니다.

보겠습니다. 귀하의 접근 방식은 "모든 숫자를 줄에 넣고 사각형이 완성되기를 바랍니다. 현재 사각형을 다루는 데 오류가있는 경우 이전 사각형을 지우십시오".

처음에는 문제가 없으므로 첫 번째 줄을 가져 오면 오류가 발생하지 않습니다. 하지만 당신은 그런 일에, 최초의 8 개 라인을 완료 한 가능성을 생각 :

1 
2 
3 
---- 
4 
5 
6 
--- 
79 
832|179|456  
x 

x에 대한 유효한 값이 없습니다. 귀하의 알고리즘은 무엇을합니까? 돌아가서 6을 바꾸려고 노력하십시오! 당연히 6을 6으로 대체하고 다시 x으로 값을 설정하려고합니다.

인터넷에서 발견 된 스도쿠스 생성기에는 유효한 해결책이 없으며 모든 변경 사항이 유효한 해결책을 제시하는 방식으로 일련의 변경을 수행합니다 (자세한 내용은 Google에 문의하십시오).

역 추적을 사용하려면 각 단계에서 스도쿠가 여전히 해결 가능한지 (아니면 적어도 "고장"이 아닌지) 검사해야합니다. 그리고 해결할 수없는 조합을 반복하지 않는 방법이 있습니다.

또한 숫자를 순서대로 넣으려고하면 처음에는 너무 강한 제약 조건을 추가하는 것처럼 보입니다. 처음 두 줄을 채우는 것은 쉽지만 전체 솔루션을 조절합니다 (첫 줄을 채우는 것은 영향을주지 않습니다! :-D).

0

나는 이것이 문제에 접근하는 좋은 방법이라고 생각지 않는다. 불행히도 나는 해결책이 없다. 그러나 일단 count == 9이 나타나면, x and y을 변경해야한다. 이는 반드시해야 할 일이 아니다. 그럼에도 불구하고 while(!valid) 루프를 종료하는 방법은 제공하지 않습니다. 실제로 되돌리려면 validtrue으로 변경해야합니다. 그러나이 방법을 사용할 수는 없습니다.