1. 程式人生 > 其它 >回溯演算法-解數獨

回溯演算法-解數獨

回溯演算法

 

什麼是回溯法?

回溯法(探索與回溯法)是一種選優搜尋法,又稱為試探法,按選優條件向前搜尋,以達到目標。但當探索到某一步時,發現原先選擇並不優或達不到目標,就退回一步重新選擇,這種走不通就退回再走的技術為回溯法,而滿足回溯條件的某個狀態的點稱為“回溯點”。

 

用回溯演算法解決問題的一般步驟:

 

1、 針對所給問題,定義問題的解空間,它至少包含問題的一個(最優)解。

 

2 、確定易於搜尋的解空間結構,使得能用回溯法方便地搜尋整個解空間 。

 

3 、以深度優先的方式搜尋解空間,並且在搜尋過程中用剪枝函式避免無效搜尋。  

 

基本思想

從一條路往前走,能進則進,不能進則退回來,換一條路再試。

 

能解決哪些問題?

  • 排列、組合(子集、冪集、字元全排列)。
  • 二維陣列下的DFS搜尋(黃金礦工、數獨、裝載問題、0-1揹包問題、旅行售貨員問題、八皇后問題、迷宮問題、圖的m著色問題

  • 陣列、字串,給定一個特定的規則,嘗試搜尋迭代找到某個解。

 

回溯的解空間

回溯演算法有兩種常見的解空間模型,分別對應數學中的兩種暴力思想,組合以及排列。其中子集問題,對應數學中的組合問題。排列問題對應數學中的排列問題。

 

解數獨

數獨,是源自18世紀瑞士的一種數學遊戲。是一種運用紙、筆進行演算的邏輯遊戲。玩家需要根據9×9盤面上的已知數字,推理出所有剩餘空格的數字,並滿足每一行、每一列、每一個粗線宮(3*3)內的數字均含1-9,不重複。

數獨盤面是個九宮,每一宮又分為九個小格。在這八十一格中給出一定的已知數字和解題條件,利用邏輯和推理,在其他的空格上填入1-9的數字。使1-9每個數字在每一行、每一列和每一宮中都只出現一次,所以又稱“九宮格”

 

 

利用回溯演算法解數獨。思路如下:

1,從0行0列開始,依次往裡面填入1-9的數字;


2,然後判斷填入這個數字後,該數字對應的行,列和九宮格是否滿足不重複的條件;


3,如果當前填入的數字滿足,就繼續填入下一個數字,下一個數字又從1-9中嘗試,如果有滿足的數字就說明該數字可用,如果沒有,則將該數字又重新置為空格,如此迴圈往復;


4,如果將所有的數字都嘗試了還是沒有合適的額,那說明本問題無解,返回false;

 1 /*
 2  *java 遞迴
 3  */
 4 public class ShuduPro {
 5     private int[][] sudoku;
 6     public
ShuduPro(int[][] sudoku) { 7 this.sudoku = sudoku; 8 } 9 public static void main(String[] args) { 10 int[][] sudoku={ 11 {7, 0, 0, 0, 0, 0, 0, 0, 9}, 12 {1, 4, 0, 3, 0, 9, 0, 0, 6}, 13 {0, 0, 0, 0, 0, 0, 5, 1, 0}, 14 {0, 0, 0, 0, 0, 0, 0, 0, 0}, 15 {0, 0, 2, 0, 8, 1, 0, 0, 0}, 16 {0, 0, 9, 0, 2, 0, 8, 0, 0}, 17 {0, 0, 0, 0, 0, 0, 0, 0, 0}, 18 {0, 2, 8, 5, 0, 6, 9, 0, 0}, 19 {0, 0, 0, 1, 0, 0, 3, 0, 2} 20 }; 21 ShuduPro sudu = new ShuduPro(sudoku); 22 sudu.backTrace(0,0); 23 } 24 private void backTrace(int i, int j) { 25 //完成,列印陣列 26 if(i==8 && j==9){ 27 print_sudoku(); 28 return; 29 } 30 //判斷是否到列尾,到列尾沒到行尾,就換行 31 if(j == 9){ 32 i++; 33 j=0; 34 } 35 36 //如果是空格就填值 37 if (sudoku[i][j] == 0){ 38 for (int n = 1; n <=9; n++){ 39 //判斷空格中填任一個數是否符合規則 40 if(check_repeat(i,j,n)){ 41 /* 42 *賦值 43 * 進入下一個空格 44 * 初始化該空格 45 */ 46 sudoku[i][j] = n; 47 backTrace(i,j+1); 48 sudoku[i][j]=0; 49 } 50 } 51 }else{ 52 backTrace(i,j+1); 53 } 54 } 55 56 /** 57 * 58 * @param row 行號 59 * @param col 列號 60 * @param temp 賦的值 61 * @return 62 */ 63 private boolean check_repeat(int row, int col, int temp) { 64 //判斷所在行和列是否有重複數字 65 for (int i=0; i < 9; i++){ 66 if(sudoku[row][i] == temp || sudoku[i][col] == temp){ 67 return false; 68 } 69 } 70 //判斷所在小九宮格中是否有重複 71 int tempRow = (row / 3) * 3; 72 int tempCol = (col / 3) * 3; 73 for (int i = 0; i < 3; i++){ 74 for (int j = 0; j < 3; j++){ 75 if(sudoku[tempRow + i][tempCol + j] == temp){ 76 return false; 77 } 78 } 79 } 80 return true; 81 } 82 83 //列印矩陣 84 private void print_sudoku() { 85 for (int i = 0; i < 9; i++){ 86 for (int j = 0; j < 9; j++){ 87 System.out.print(sudoku[i][j]+" "); 88 } 89 System.out.println(" "); 90 } 91 System.out.println(" "); 92 } 93 94 }