2013-06-22 24 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

我從來沒有做過回溯無w/o遞歸;現在我想我知道爲什麼。通過程序執行開始跟蹤。從較小的電路板開始。 –

+1

不要在循環中更改'for'的索引,這是妨礙編譯器優化代碼的錯誤做法。 – SJuan76

回答

1

可能會發生許多問題。我只是舉個例子。

回溯不起作用的主要原因是因爲你沒有做回溯。你只返回樹中的一個狀態,回溯意味着你檢查一個子樹的所有可能性,然後(如果沒有一個是有效的),你忽略該子樹,不管它多高。

讓我們來看看。你的方法是「把所有的數字排成一行,並希望廣場完成,如果處理當前廣場出現錯誤,請清除前一個廣場」。

開始時沒有問題,獲取第一行不會導致錯誤。不過想到你已經完成了第8行,用類似的東西的可能性:

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

沒有爲x沒有有效的價值。你的算法做什麼?回去嘗試改變6!不出所料,這將以以6代替6而結束,並且再次嘗試將值設置爲x

我在互聯網上找到的Sudokus生成器沒有回溯,只需要採取有效的解決方案並對其進行一系列更改,以便所有更改都帶來有效的解決方案(有關更多詳細信息,請詢問Google)。

如果你想使用回溯,在每一步你應該掃描數獨是否仍然可以解決(或者至少,這不是「破」)。並有一種不重複不可解的組合的方法。

此外,試圖按順序放置數字看起來(這是一種觀點)在開始時添加一個太強的約束。填寫前兩行很容易,但它會影響整個解決方案(請注意,填寫第一行不會影響它!:-D)。

0

我不認爲這是解決問題的好方法;不幸的是,我沒有解決方案,但我確實看到一次count == 9,您更改x and y,這不是一件好事。但是,您不提供終止while(!valid)循環的方法。您需要將valid更改爲true以實際回溯;但是,這不會使該方法起作用。