题目描述
补充完整9*9的数独
基本分析
- 深搜的维度是什么?还有多少个空没填
- 每次进行搜索时候怎么进行最优化?从所有的可能中找确定性最高的一个分支
- 状态压缩
(1)怎么判断行、列、格子中应该填哪些数字?每一行、或者列、或者格子内的值都是一个9位的二进制值,某位置是1表示这个值可填。
(2)怎么综合行,列、格子的情况判断哪些数字可填?对给定的(x, y)坐标,会查到3个mask值,3个mask取&的最终mask就是可填的数字
(3)怎么赋初值?对给定的每个非"."的值,利用索引k拿到对应1值,进而知道哪一位需要置为0
- dfs的返回值?cnt是0的时候true; 修改状态后如果dfs(cnt - 1)true, 返回true;否则返回false;
- 怎么进行预处理?
(1)ones数组保存每个mask对应的1的个数
(2)map数组保存1 << x这个值对应的1的位置,也就是x值
(3)求mask的最后一个1的位置,用lowbit;不断-取lowbit(i),可以遍历出i中所有1的位置。
代码
| #include <iostream> |
| #include <algorithm> |
| |
| using namespace std; |
| |
| const int N = 9; |
| |
| int ones[1 << N], map[1 << N]; |
| int row[N], col[N], cell[3][3]; |
| char str[100]; |
| |
| |
| inline int lowbit(int x) |
| { |
| return x & -x; |
| } |
| |
| inline int get(int x, int y) |
| { |
| return row[x] & col[y] & cell[x / 3][y / 3]; |
| } |
| |
| void init() |
| { |
| for (int i = 0; i < N; i++) |
| row[i] = col[i] = (1 << N) - 1; |
| |
| for (int i = 0; i < 3; i++) |
| for (int j = 0; j < 3; j++) |
| cell[i][j] = (1 << N) - 1; |
| } |
| |
| bool dfs(int cnt) |
| { |
| if (!cnt) |
| return true; |
| |
| |
| int minv = 10; |
| int x, y; |
| for (int i = 0; i < N; i++) |
| for (int j = 0; j < N; j++) |
| if (str[i * 9 + j] == '.') |
| { |
| |
| int t = ones[get(i, j)]; |
| |
| if (t < minv) |
| { |
| minv = t; |
| x = i, y = j; |
| } |
| } |
| |
| |
| for (int i = get(x, y); i; i -= lowbit(i)) |
| { |
| |
| int t = map[lowbit(i)]; |
| |
| |
| row[x] -= 1 << t; |
| col[y] -= 1 << t; |
| cell[x / 3][y / 3] -= 1 << t; |
| str[x * 9 + y] = '1' + t; |
| |
| |
| if (dfs(cnt - 1)) |
| return true; |
| |
| |
| row[x] += 1 << t; |
| col[y] += 1 << t; |
| cell[x / 3][y / 3] += 1 << t; |
| str[x * 9 + y] = '.'; |
| } |
| |
| return false; |
| } |
| |
| int main() |
| { |
| |
| for (int i = 0; i < N; i ++) |
| map[1 << i] = i; |
| |
| |
| for (int i = 0; i < 1 << N; i++) |
| { |
| int s = 0; |
| |
| for (int j = i; j; j -= lowbit(j)) |
| s ++; |
| ones[i] = s; |
| } |
| |
| while (cin >> str, str[0] != 'e') |
| { |
| init(); |
| |
| |
| int cnt = 0; |
| int k = 0; |
| for (int i = 0; i < N; i++) |
| for (int j = 0; j < N; j++, k++) |
| if (str[k] != '.') |
| { |
| |
| int t = str[k] - '1'; |
| row[i] -= 1 << t; |
| col[j] -= 1 << t; |
| cell[i / 3][j / 3] -= 1 << t; |
| } |
| else |
| cnt ++; |
| dfs(cnt); |
| |
| cout << str << endl; |
| } |
| } |
总结
- 判断某个位置可选的数字?row[x] & col[y] & cell[x / 3][y / 3]
- 减枝:分枝最少的位置(x, y)
- 向下搜索的分支?枚举最少位置可填的数字
- dfs的逻辑?枚举可行的分支(修改状态, 向下, 恢复现场)
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 使用C#创建一个MCP客户端
· ollama系列1:轻松3步本地部署deepseek,普通电脑可用
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· 按钮权限的设计及实现