首页 最新 热门 推荐

  • 首页
  • 最新
  • 热门
  • 推荐

【回溯 状态压缩 深度优先】37. 解数独

  • 25-02-22 05:01
  • 2153
  • 5305
blog.csdn.net

本文涉及知识点

回溯 状态压缩 深度优先

LeetCode37. 解数独

编写一个程序,通过填充空格来解决数独问题。
数独的解法需 遵循如下规则:
数字 1-9 在每一行只能出现一次。
数字 1-9 在每一列只能出现一次。
数字 1-9 在每一个以粗实线分隔的 3x3 宫内只能出现一次。(请参考示例图)
数独部分空格内已填入了数字,空白格用 ‘.’ 表示。

示例 1:
输入:board = [[“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”]]
在这里插入图片描述

输出:[[“5”,“3”,“4”,“6”,“7”,“8”,“9”,“1”,“2”],[“6”,“7”,“2”,“1”,“9”,“5”,“3”,“4”,“8”],[“1”,“9”,“8”,“3”,“4”,“2”,“5”,“6”,“7”],[“8”,“5”,“9”,“7”,“6”,“1”,“4”,“2”,“3”],[“4”,“2”,“6”,“8”,“5”,“3”,“7”,“9”,“1”],[“7”,“1”,“3”,“9”,“2”,“4”,“8”,“5”,“6”],[“9”,“6”,“1”,“5”,“3”,“7”,“2”,“8”,“4”],[“2”,“8”,“7”,“4”,“1”,“9”,“6”,“3”,“5”],[“3”,“4”,“5”,“2”,“8”,“6”,“1”,“7”,“9”]]
解释:输入的数独如上图所示,唯一有效的解决方案如下所示:
提示:
在这里插入图片描述

board.length == 9
board[i].length == 9
board[i][j] 是一位数字或者 ‘.’
题目数据 保证 输入数独仅有一个解

回溯

vRow[i] 记录第i行可以选择那些数,vCol[i]和vCell类型。
vRow[i] & ( 1 << j) 表示第i行,可以选择数组j。
直接将选择结果修改到board上。
vector> vSel。 i1,记录可以选择的数量,i2记录行号,i3记录列号。注意:只需要记录能修改的数组。 初始化结束后,对vSel排序。理论上:只有一种选择的先选快点。实际上几乎无影响。
用深度优先实现。Fill 函数填写某行某列,UnFill 恢复某行某列原装。
时间复杂度:不好计算。

代码

核心代码

class CBitCounts
{
public:
	CBitCounts(int iMaskCount)
	{
		for (int i = 0; i < iMaskCount; i++)
		{
			m_vCnt.emplace_back(bitcount(i));
		}
	}
	template<class T>
	static int bitcount(T x) {
		int countx = 0;
		while (x) {
			countx++;
			x &= (x - 1);
		}
		return countx;
	}
	vector<int> m_vCnt;
};

class Solution {
public:
	void solveSudoku(vector<vector<char>>& board) {
		m_board = board;
		int mask = 0;
		for (int i = 1; i <= 9; i++) {
			mask |= (1 << i);
		}
		for (int i = 0; i < 9; i++) {
			m_rows[i] = m_cols[i] = m_cells[i] = mask;
		}
		
		for (int r = 0; r < 9; r++) {
			for (int c = 0; c < 9; c++) {
				if ('.' == board[r][c]) { continue; }
				Fill(r, c, board[r][c] - '0');
			}
		}
		vector<tuple<int, int, int,int>> vSel;
		for (int r = 0; r < 9; r++) {
			for (int c = 0; c < 9; c++) {
				if ('.' != board[r][c]) { continue; }
				int iCell = r / 3 * 3 + c / 3;
				int mask = m_rows[r] & m_cols[c] & m_cells[iCell];
				vSel.emplace_back(CBitCounts::bitcount(mask), r, c,iCell);
			}
		}
		sort(vSel.begin(), vSel.end());
		DFS(vSel, 0);
		board = m_board;
	}
	bool DFS(const vector<tuple<int, int, int,int>> vSel, int leve) {
		if (vSel.size() == leve) { return true; }
		const auto& [tmp, r, c, iCell] = vSel[leve];
		int mask = m_rows[r] & m_cols[c] & m_cells[iCell];
		for (int i = 1; i <= 9; i++) {
			if (mask & (1 << i)) {
				Fill(r, c, i);
				if (DFS(vSel, leve + 1)) { return true; }
				UnFill(r, c, i);
			}
		}
		return false;
	}
	void Fill (int r, int c, int val) {
		m_board[r][c] = val + '0';
		m_rows[r] &= ~(1 << val);
		m_cols[c] &= ~(1 << val);
		int iCell = r / 3 * 3 + c / 3;
		m_cells[iCell] &= ~(1 << val);
	};
	void UnFill(int r, int c, int val) {
		m_board[r][c] = '.';
		m_rows[r] |= (1 << val);
		m_cols[c] |= (1 << val);
		int iCell = r / 3 * 3 + c / 3;
		m_cells[iCell] |= (1 << val);
	};
	vector<vector<char>> m_board;
	int m_rows[9], m_cols[9], m_cells[9];
};
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83

测试用例

template<class T>
void Assert(const vector<T>& v1, const vector<T>& v2)
{
	if (v1.size() != v2.size())
	{
		assert(false);
		return;
	}
	for (int i = 0; i < v1.size(); i++)
	{
		assert(v1[i] == v2[i]);
	}
}

template<class T>
void Assert(const T& t1, const T& t2)
{
	assert(t1 == t2);
}

int main()
{
	vector<vector<char>> board;
	{
		Solution slu;
		board ={ {'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' }};
		 slu.solveSudoku(board);
		 vector<vector<char>> board1={ {'5', '3', '4', '6', '7', '8', '9', '1', '2'}, { '6','7','2','1','9','5','3','4','8' }, { '1','9','8','3','4','2','5','6','7' }, { '8','5','9','7','6','1','4','2','3' }, { '4','2','6','8','5','3','7','9','1' }, { '7','1','3','9','2','4','8','5','6' }, { '9','6','1','5','3','7','2','8','4' }, { '2','8','7','4','1','9','6','3','5' }, { '3','4','5','2','8','6','1','7','9' }};
		Assert(board1, board);
	}	
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31

2023年5月代码

记录已经选择的数,这样初始化简单。用二维数组记录3 × \times × 3 网格的情况,减少计算网格号。

class Solution {
public:
	void solveSudoku(vector<vector<char>>& board) {
		memset(m_aRows, 0, sizeof(m_aRows));
		memset(m_aCols, 0, sizeof(m_aCols));
		memset(m_aBlock, 0, sizeof(m_aBlock));
		
		for (int r = 0; r < 9; r++)
		{
			for (int c = 0; c < 9; c++)
			{
				const char& ch = board[r][c];
				if ('.' == ch)
				{
					m_vNeedDoRowCols.emplace_back(r, c);
					continue;
				}
				Add(r, c, ch - '1');
			}
		}
		dfs(board, 0);
	}
	bool dfs(vector<vector<char>>& board,int iLeve)
	{
		if (m_vNeedDoRowCols.size() == iLeve)
		{
			return true;
		}
		const int r = m_vNeedDoRowCols[iLeve].first;
		const int c = m_vNeedDoRowCols[iLeve].second;
		int iMask = m_aRows[r] | m_aCols[c] | m_aBlock[r/3][c/3];
		for (int i = 0; i < 9; i++)
		{
			if (iMask & (1 << i))
			{
				continue;
			}
			Add(r, c, i);
			board[r][c] = '1' + i;
			if (dfs(board, iLeve + 1))
			{
				return true;
			}
			board[r][c] = '.';
			Erase(r, c, i);
		}
		return false;
	}
	void Add(int r, int c, int iNum)
	{
		const int iMask = 1 << iNum;
		m_aRows[r] |= iMask;
		m_aCols[c] |= iMask;
		m_aBlock[r / 3][c / 3] |= iMask;
	}
	void Erase(int r, int c, int iNum)
	{
		const int iMask = 1 << iNum;
		m_aRows[r] -= iMask;
		m_aCols[c] -= iMask;
		m_aBlock[r / 3][c / 3] -= iMask;
	}
	int m_aRows[9],m_aCols[9];
	int m_aBlock[3][3];
	vector<std::pair<int, int>> m_vNeedDoRowCols;
};
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
文章知识点与官方知识档案匹配,可进一步学习相关知识
算法技能树首页概览61211 人正在系统学习中
群中有博文配套源码
QQ群名片
注:本文转载自blog.csdn.net的闻缺陷则喜何志丹的文章"https://blog.csdn.net/he_zhidan/article/details/138321265"。版权归原作者所有,此博客不拥有其著作权,亦不承担相应法律责任。如有侵权,请联系我们删除。
复制链接
复制链接
相关推荐
发表评论
登录后才能发表评论和回复 注册

/ 登录

评论记录:

未查询到任何数据!
回复评论:

分类栏目

后端 (14832) 前端 (14280) 移动开发 (3760) 编程语言 (3851) Java (3904) Python (3298) 人工智能 (10119) AIGC (2810) 大数据 (3499) 数据库 (3945) 数据结构与算法 (3757) 音视频 (2669) 云原生 (3145) 云平台 (2965) 前沿技术 (2993) 开源 (2160) 小程序 (2860) 运维 (2533) 服务器 (2698) 操作系统 (2325) 硬件开发 (2491) 嵌入式 (2955) 微软技术 (2769) 软件工程 (2056) 测试 (2865) 网络空间安全 (2948) 网络与通信 (2797) 用户体验设计 (2592) 学习和成长 (2593) 搜索 (2744) 开发工具 (7108) 游戏 (2829) HarmonyOS (2935) 区块链 (2782) 数学 (3112) 3C硬件 (2759) 资讯 (2909) Android (4709) iOS (1850) 代码人生 (3043) 阅读 (2841)

热门文章

101
推荐
关于我们 隐私政策 免责声明 联系我们
Copyright © 2020-2025 蚁人论坛 (iYenn.com) All Rights Reserved.
Scroll to Top