解數獨(回溯)

在這裏插入圖片描述
在這裏插入圖片描述
我覺得這題的思路還是很簡單的,回溯法
就是模擬人解數獨時的簡單想法:

人在解數獨的時候要注意每一行、每一列、每一個子數獨中哪些數字已經被使用過了;

一行一行的進行填充,填充完一行就到下一行繼續填充;

如果一個單元格中不爲空,則去下一個單元格;

如果一個單元格爲空,我們就看一下這個單元格所屬的行、列、子數獨中有哪些數字沒有使用過,就將未使用過的數字填入單元格,並且記錄這個被填入的數字在此單元格所屬的行、列、子數獨中已經被使用過了;

如果出現因爲之前填充空格時選擇不佳,導致無法繼續填寫空格的情況,就逐步擦除之前填入的數字,並將被擦除的數字在所屬的行、列、子數獨中設置爲未使用的狀態後,重新選擇下一個未使用過的數字進行填充,嘗試繼續完成填充;

如果已經填充完所有行,即成功解數獨。

思路理清後,代碼很快就寫好了:

class Solution {
public:
	void solveSudoku(vector<vector<char>>& board) {
		for (int i = 0; i < 9; i++)
			for (int j = 0; j < 9; j++)
			{
				if (board[i][j] != '.')
				{
					rows[i][board[i][j] - '0' - 1] = true;
					cols[j][board[i][j] - '0' - 1] = true;
					blocks[i / 3 * 3 + j / 3][board[i][j] - '0' - 1] = true;
				}
			}

		DFS(board, 0, 0);
	}
	//深度遍歷,row記錄當前要填寫的行,col記錄當前要填寫的列
	void DFS(vector<vector<char>>& board, int row, int col)
	{
		//0-8行都已經填寫,解數獨完畢
		if (row == 9) {
			finished = true;
			return;
		}
		//不是空白格,不需要填寫,繼續向後移動
		if (board[row][col] != '.')
		{
			//如果本行已經是最後一列,則繼續填寫下一行的第一列;否則繼續當前行的下一列。
			if (col == 8) DFS(board, row + 1, 0);
			else DFS(board, row, col + 1);
		}
		else//是空白格,按順序將當前行、列、子數獨未使用的數字嘗試填入空白格
		{
			for (char number = '1'; number <= '9'; number++)
			{
				if (!rows[row][number - '0' - 1] && !cols[col][number - '0' - 1] && !blocks[row / 3 * 3 + col / 3][number - '0' - 1])
				{
					board[row][col] = number;
					rows[row][number - '0' - 1] = cols[col][number - '0' - 1] = blocks[row / 3 * 3 + col / 3][number - '0' - 1] = true;
					//填寫完畢當前空白格,繼續填寫下一格
					if (col == 8)DFS(board, row + 1, 0);
					else DFS(board, row, col + 1);
					//如果當前嘗試填入的數字不能成功解數獨(導致後序空白格無法填寫),則回溯
					if (!finished)
					{
						//擦除填入的數字,並更新被擦除數字的狀態
						board[row][col] = '.';
						rows[row][number - '0' - 1] = cols[col][number - '0' - 1] = blocks[row / 3 * 3 + col / 3][number - '0' - 1] = false;
					}
				}
			}
		}

	}



private:
	bool rows[9][9] = { false };//rows[i][j]爲true表示第i+1行的數字j+1已經被使用了
	bool cols[9][9] = { false };//cols[i][j]爲true表示第i+1列的數字j+1已經被使用了
	bool blocks[9][9] = { false };//cols[i][j]爲true表示第i+1個子數獨中數字j+1已經被使用了
	bool finished = false;
};

在這裏插入圖片描述

在這裏插入圖片描述
在這裏插入圖片描述

class Solution {
public:
	bool isValidSudoku(vector<vector<char>>& board) {

		for (int row = 0; row < 9; ++row)
			for (int col = 0; col < 9; ++col)
			{
				if (board[row][col] != '.')
				{
					if (!rows[row][board[row][col] - '0' - 1] && !cols[col][board[row][col] - '0' - 1] && !blocks[row / 3 * 3 + col / 3][board[row][col] - '0' - 1])
						rows[row][board[row][col] - '0' - 1] = cols[col][board[row][col] - '0' - 1] = blocks[row / 3 * 3 + col / 3][board[row][col] - '0' - 1] = true;
					else
						return false;
				}
			}
		return true;
	}


private:
	bool rows[9][9] = { false };//rows[i][j]爲true表示第i+1行的數字j+1已經被使用了
	bool cols[9][9] = { false };//cols[i][j]爲true表示第i+1列的數字j+1已經被使用了
	bool blocks[9][9] = { false };//cols[i][j]爲true表示第i+1個子數獨中數字j+1已經被使用了
};
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章