算法设计与分析Leetcode第七周

37.Sudoku Solver
Difficulty:Hard
Total Accepted:105.3K
Total Submissions:311.2K
https://leetcode.com/problems/sudoku-solver/description/

Write a program to solve a Sudoku puzzle by filling the empty cells.

A sudoku solution must satisfy all of the following rules:

Each of the digits 1-9 must occur exactly once in each row.
Each of the digits 1-9 must occur exactly once in each column.
Each of the the digits 1-9 must occur exactly once in each of the 9 3x3 sub-boxes of the grid.
Empty cells are indicated by the character ‘.’.

在这里插入图片描述
A sudoku puzzle…
在这里插入图片描述
…and its solution numbers marked in red.

Note:

The given board contain only digits 1-9 and the character ‘.’.
You may assume that the given Sudoku puzzle will have a single unique solution.
The given board size is always 9x9.

思路:利用回溯法

回溯法有通用解法的美称,对于很多问题,如迷宫等都有很好的效果。回溯算法实际上一个类似枚举的深度优先搜索尝试过程,主要是在搜索尝试过程中寻找问题的解,当发现已不满足求解条件时,就“回溯”返回(也就是递归返回),尝试别的路径。许多复杂的,规模较大的问题都可以使用回溯法,有“通用解题方法”的美称。回溯法说白了就是穷举法。回溯法一般用递归来解决。

递归思路:

  1. 读取数独的初始状态,填入sudoku变量
  2. 在读取数独的初始状态的同时,并初始化数字的可填区域,填入flag变量
  3. 在读取数独的初始状态的同时,更新数独的数字占用情况,填入rule变量
  4. 开始求解数独,进入首层递归
  5. 获取下一个可填区域的位置
  6. 若当前位置已超出期望,表明已得出数独的解,打印结果并回溯到上一层进行求解
  7. 查找当前位置的数字占用情况,对三条规则进行交集运算,得出下一个可填数。如果超出期望,回溯到上一层进行求解
  8. 修改当前位置的可填数,并更新对应数字的占用状态为已占用
  9. 以当前的坐标作为实参进入下一层递归,返回步骤5
  10. 修改当前位置的可填数,并更新对应数字的占用状态为未占用(失败,重新归为)
class Solution {
public:
	bool flag[9][9] = { false };//对应位置的数字被确定
	bool rule[3][9][9] = { false };//对应的行/列/块的某个数字是否已经出现过
	int size = 0;
	void solveSudoku(vector<vector<char>>& board) {
		init(board);
		solve(0, 0, board);
	}
	void solve(int row,int col,vector<vector<char>>& board) {
		if ( col==9 ) {
			col = 0;
			row++;
		}
		while (row < 9 && flag[row][col++]) {//过掉已经确定的数字
			if (col == 9) {
				col = 0;
				row++;
			}
		}
		if (row == 9) {//已经全部位置确定
			return;
		}
		while (1) {
			board[row][col] = findNextValue(row,col,0,board);//假设该位置的值为某个数
			if (board[row][col]!=-1) {
				changeRule(row, col, true, board);
				solve(row, ++col, board);
				changeRule(row, col, true, board);
			}
		}
	}
	void init(vector<vector<char>>& board) {
		size = board.size();
		int value = 0;
		for (int i = 0; i < size; i++) {
			for (int j = 0; j < size; j++) {
				if (board[i][j]!= '.') {
					flag[i][j] = true;
					value = board[i][j] - '0'-1;
					rule[0][i][value] = true;
					rule[1][j][value] = true;
					rule[2][findBlockNum(i, j)][value] = true;
				}
			}
		}
	}
	int findNextValue(int row,int col,int start, vector<vector<char>>& board) {
		for (int i = start; i < board.size(); i++) {
			if ( rule[0][row][i]||rule[1][col][i]||rule[2][findBlockNum(row,col)][i] )continue;
			return i;
		}
		return -1;//未找到
	}
	void changeRule(int row,int col,bool B, vector<vector<char>>& board) {
		int value = board[row][col] - '0' - 1;
		rule[0][row][value] = B;
		rule[1][col][value] = B;
		rule[2][findBlockNum(row, col)][value] = B;
	}
	int findBlockNum(int row, int col) {
		return (3 * (row / 3) + (col / 3));
	}
};
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值