一 、運用 回溯法 解數獨
- 回溯法算法思想:(參考 回溯法)
定義:
回溯法(探索與回溯法)是一種選優搜索法,按選優條件向前搜索,以達到目標。但當探索到某一步時,發現原先選擇並不優或達不到目標,就退回一步重新選擇,這種走不通就退回再走的技術爲回溯法,而滿足回溯條件的某個狀態的點稱爲“回溯點”。
1、回溯法適用:有許多問題,當需要找出它的解集(全部解)或者要求回答什麼解是滿足某些約束條件的最優解時,往往要使用回溯法。
2、有組織的窮舉式搜索:回溯法的基本做法是搜索或者有的組織窮盡搜索。它能避免搜索所有的可能性。即避免不必要的搜索。這種方法適用於解一些組合數相當大的問題。
3、搜索解空間樹:回溯法在問題的解空間樹中,按深度優先策略,從根結點出發搜索解空間樹。算法搜索至解空間樹的任意一點時,先判斷該結點是否包含問題的解。如果肯定不包含(剪枝過程),則跳過對該結點爲根的子樹的搜索,逐層向其祖先結點回溯;否則,進入該子樹,繼續按深度優先策略搜索。
找到子數獨法
let boxRow = (parseInt(row/3)*3)+parseInt(i/3); //子數獨行標
let boxCol = (parseInt(col/3)*3)+i%3;//子數獨列標
算法
- 行循環,嵌套列循環
- 找到沒有數字的數組
if (board[i][j] == '.') {}
- 開始嘗試填寫數字1-9,isValid 檢驗填充數字是否有重複。有重複就回溯重新開始
for(let num = 1; num<10; num++) {
//檢驗填充數字的正確性
if (isValid(i,j,num)) {
board[i][j] = String(num);
//遞歸
if (solve(board)) {
return true;
}
board[i][j] = '.';
}
}
let isValid = (row,col,num) => {
//定位到每個小格子的座標
for (let i = 0; i < 9; i++) {
let boxRow = (parseInt(row/3)*3)+parseInt(i/3); //子數獨行標
let boxCol = (parseInt(col/3)*3)+i%3;//子數獨列標
//console.log(boxRow + '_' + boxCol);
if (board[row][i] == num || board[i][col] == num || board[boxRow][boxCol] == num) {
return false;
}
}
return true;
}
完整代碼 js
var sd = new solveSudoku([
["5", "3", ".", ".", "7", ".", ".", ".", "."],
["6", ".", ".", "1", "9", "5", ".", ".", "."],
[".", "9", "8", ".", ".", ".", ".", "6", "."],
["8", ".", ".", ".", "6", ".", ".", ".", "3"],
["4", ".", ".", "8", ".", "3", ".", ".", "1"],
["7", ".", ".", ".", "2", ".", ".", ".", "6"],
[".", "6", ".", ".", ".", ".", "2", "8", "."],
[".", ".", ".", "4", "1", "9", ".", ".", "5"],
[".", ".", ".", ".", "8", ".", ".", "7", "9"]
]);
/**
* @param {character[][]} board
* @return {void} Do not return anything, modify board in-place instead.
*/
var solveSudoku = function (board) {
//檢驗填充數字的正確性 row 行 col列 num 填充數字
let isValid = (row,col,num) => {
//循環嘗試填充數字
for (let i = 0; i < 9; i++) {
let boxRow = (parseInt(row/3)*3)+parseInt(i/3); //子數獨行標
let boxCol = (parseInt(col/3)*3)+i%3;//子數獨列標
//console.log(boxRow + '_' + boxCol);
if (board[row][i] == num || board[i][col] == num || board[boxRow][boxCol] == num) {
return false;
}
}
return true;
}
//聲明一個塊級變量
let solve =() => {
//循環行
for (let i = 0; i < 9; i++) {
//循環列
for (let j = 0; j < 9; j++) {
//判斷填充資格
if (board[i][j] == '.') {
//開始循環數字
for(let num = 1; num<10; num++) {
//檢驗填充數字的正確性
if (isValid(i,j,num)) {
board[i][j] = String(num);
//遞歸
if (solve(board)) {
return true;
}
board[i][j] = '.';
}
}
return false;
}
}
}
return true;
}
solve(board);
console.log(board);
return board;
};