前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >利用计算机程序快速得到9*9大小数独的解法

利用计算机程序快速得到9*9大小数独的解法

作者头像
全栈程序员站长
发布2022-11-01 15:42:40
3350
发布2022-11-01 15:42:40
举报
文章被收录于专栏:全栈程序员必看

对于 9 ∗ 9 9*9 9∗9 大小的数独游戏,我们可以使用回溯法求得其正确的解,但是,一般的回溯法实现这个过程保证不了时间复杂度,所以我们可以利用二进制压缩的方法来优化其过程。

具体思路如下:

明确数独的约束:

  • 相同一行不能出现重复的数
  • 相同一列不能出现重复的数
  • 同一宫内不能出现重复的数

定义 r o w [ i ] row[i] row[i]数组代表,第 i , j i,j i,j位置,在 i i i 行哪些数被占用,用二进制 1 1 1 表示没有被占用, 0 0 0 表示被占用那么最开始 r o w [ i ] row[i] row[i] = 111111111 111111111 111111111,表示行没有数被占用。

定义 c o l [ j ] col[j] col[j]数组代表,第 i , j i,j i,j位置,第 j j j 列哪些数被占用,用二进制 1 1 1 表示没有被占用, 0 0 0 表示被占用,那么最开始 c o l [ i ] col[i] col[i] = 111111111 111111111 111111111,表示列没有数被占用。

定义 c e l l [ i / 3 ] [ j / 3 ] cell[i/3][j/3] cell[i/3][j/3]数组代表,第 i , j i,j i,j 格所在的宫中那些数被占用,用二进制 1 1 1 表示没有被占用, 0 0 0 表示被占用,那么最开始 c e l l [ i / 3 ] [ j / 3 ] cell[i/3][j/3] cell[i/3][j/3] = 111111111 111111111 111111111,表示宫中没有数被占用。

然后我们需要初始化上面三个数组,因为一开始的数独游戏位置被一些数占用了,那么这些数的位置就会影响 r o w [ i ] , c o l [ j ] , c e l l [ i ] [ j ] row[i],col[j],cell[i][j] row[i],col[j],cell[i][j]的二进制数,我们需要把相应的数,在二进制数的响应位改变成0,表示这个数在此列或行或宫被占用了。

然后我们利用位运算&对三个数组进行&,就可以得到三个数组都没有被占用的数,然后从其中挑选数,进行回溯法即可得到数独的解。

注意要熟悉: l o w b i t ( ) lowbit() lowbit()的用法,是取二进制数第一次出现 1 1 1时的大小,例如 100100 100100 100100,这个数的 l o w b i t ( ) lowbit() lowbit()就是 100 100 100,在这个程序中他用来取&后的数字的二进制可用数是多少,这个可用数我们也提前预处理,映射到了 m a p [ ] map[] map[]数组里,然后这个还有一个贪心策略,即当可用数越少答案就越确定,我们用 o n e s [ ] ones[] ones[]数组记录一下所有可出现状态的1的数量,1的数量少代表当前位置越确定,这个可以对程序执行很大的优化。

下面以一个数独游戏为例: 被解决的数独游戏:

在这里插入图片描述
在这里插入图片描述

程序跑出的解: 输入的时候空位置用.代替即可

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

可执行代码:

代码语言:javascript
复制
#include <algorithm>
#include <iostream>
using namespace std;
const int N = 9;
int row[N], col[N], cell[3][3], ones[1 << N], map[1 << N], cnt;
char s[N][N];
inline int lowbit(int x) { 

return (x & -x);
}
inline 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;
}
inline int get(int x, int y) { 

return row[x] & col[y] & cell[x / 3][y / 3];
}
bool dfs(int cnt) { 

if (!cnt)
return true;
int x, y, mav = 10;
for (int i = 0; i < N; i++) { 

for (int j = 0; j < N; j++) { 

if (s[i][j] == '.') { 

int t = ones[get(i, j)];
if (mav > t) { 

mav = 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;
s[x][y] = '1' + t;
if (dfs(cnt - 1))
return true;
row[x] += 1 << t;
col[y] += 1 << t;
cell[x / 3][y / 3] += 1 << t;
s[x][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 k = 0;
for (int j = i; j; j -= lowbit(j)) { 

k++;
}
ones[i] = k;
}
while (true) { 

for (int i = 0; i < N; i++)
cin >> s[i];
init();
cnt = 0;
for (int i = 0; i < 9; i++) { 

for (int j = 0; j < 9; j++) { 

if (s[i][j] != '.') { 

int t = s[i][j] - '1';
row[i] -= 1 << t;
col[j] -= 1 << t;
cell[i / 3][j / 3] -= 1 << t;
} else { 

cnt++;
}
}
}
dfs(cnt);
for (int i = 0; i < N; i++) { 

for (int j = 0; j < N; j++) { 

cout << s[i][j] << ' ';
}
cout << endl;
}
}
return 0;
}

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

发布者:全栈程序员栈长,转载请注明出处:https://javaforall.cn/200817.html原文链接:https://javaforall.cn

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2022年10月22日,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档