在网上看到一个特别简短的DFS求解数独C程序,
我把输入改成一个字符串。
#include <iostream>
#include <algorithm>
#include <cstdio>
#include <cmath>
using namespace std;
bool hang[10][10],lie[10][10],fz[10][10];//做记录
//例如 hang[1][2]=1,代表第一行有数字2
// lie[3][4]=1,代表第3列有数字4
// fz[1][5]=1,代表方针1有数字5
int sd[10][10];//代表数独的元素
// 输出
void print1() {
for(int i=1;i<=9;i++) {
for(int j=1;j<=9;j++) {
cout<<sd[i][j]<<" ";
}
cout<<endl;
}
//system("pause");
exit(0);
}
//做记录
void record(int x,int y) {
hang[x][sd[x][y]]=1;
lie[y][sd[x][y]]=1;
fz[(x-1)/3*3+(y-1)/3+1][sd[x][y]]=1;
}
//销毁记录
void derecord(int x,int y) {
hang[x][sd[x][y]]=0;
lie[y][sd[x][y]]=0;
fz[(x-1)/3*3+(y-1)/3+1][sd[x][y]]=0;
sd[x][y]=0;
}
void dfs(int x,int y) {
//当这个数原本就有
if(sd[x][y]!=0) {
//当搜到(9,9)时候,全部已经弄完,就输出结果
if(x==9 && y==9) print1();
//当搜到(x,9)时,说明这一行已经搜完了,该搜下一行了
else if(y==9) dfs(x+1,1);
//以上都不满足就搜这行的下一个数
else dfs(x,y+1);
}
//当这个数原本没有
else {
//循环遍历,依次输入1-9,一次一次试。
for(int i=1;i<=9;i++) {
//如果这行,列,方阵都没有i这个数,就可以假设它是i
if((!hang[x][i]) && (!lie[y][i]) && (!fz[(x-1)/3*3+(y-1)/3+1][i])) {
//先假设是i
sd[x][y]=i;
// 做记录
record(x,y);
//当搜到(9,9)时候,全部已经弄完,就输出结果
if(x==9 && y==9) print1();
//当搜到(x,9)时,说明这一行已经搜完了,该搜下一行了
else if(y==9) dfs(x+1,1);
//以上都不满足就搜这行的下一个数
else dfs(x,y+1);
//下一个格子1-9都找不到,说明假设不成立,就销毁已经做了的记录,就假设是下一个数
derecord(x,y);
}
}
//1-9都假设完了,发现还不满足,说明上一个格子假设有问题,返回上一个格子
return;
}
}
int main() {
char s[82]="";
cin>>s;
for(int i=1;i<=9;i++) {
for(int j=1;j<=9;j++) {
sd[i][j]=s[(i-1)*9+j-1]-'0';
// 不是0就做记录
if(sd[i][j]) {
record(i,j);
}
}
}
dfs(1,1);
cout<<"该数独无解"<<endl;
//system("pause");
return 0;
}
让DeepSeek改写成Python,
import sys
import time
class SudokuSolver:
def __init__(self):
self.r = [[False] * 10 for _ in range(10)] # 行记录
self.c = [[False] * 10 for _ in range(10)] # 列记录
self.g = [[False] * 10 for _ in range(10)] # 宫记录
self.sd = [[0] * 10 for _ in range(10)] # 数独数组
def print_sudoku(self):
"""输出数独结果"""
for i in range(1, 10):
for j in range(1, 10):
print(self.sd[i][j], end=" ")
print()
print()
def record(self, x, y):
"""做记录"""
num = self.sd[x][y]
self.r[x][num] = True
self.c[y][num] = True
g_index = (x - 1) // 3 * 3 + (y - 1) // 3 + 1
self.g[g_index][num] = True
def derecord(self, x, y):
"""销毁记录"""
num = self.sd[x][y]
self.r[x][num] = False
self.c[y][num] = False
g_index = (x - 1) // 3 * 3 + (y - 1) // 3 + 1
self.g[g_index][num] = False
self.sd[x][y] = 0
def dfs(self, x, y):
"""深度优先搜索求解"""
# 当这个数原本就有
if self.sd[x][y] != 0:
# 当搜到(9,9)时候,全部已经弄完,就输出结果
if x == 9 and y == 9:
self.print_sudoku()
return True
# 当搜到(x,9)时,说明这一行已经搜完了,该搜下一行了
elif y == 9:
return self.dfs(x + 1, 1)
# 以上都不满足就搜这行的下一个数
else:
return self.dfs(x, y + 1)
# 当这个数原本没有
else:
# 循环遍历,依次输入1-9,一次一次试
for i in range(1, 10):
g_index = (x - 1) // 3 * 3 + (y - 1) // 3 + 1
# 如果这行,列,方阵都没有i这个数,就可以假设它是i
if not self.r[x][i] and not self.c[y][i] and not self.g[g_index][i]:
# 先假设是i
self.sd[x][y] = i
# 做记录
self.record(x, y)
result = False
# 当搜到(9,9)时候,全部已经弄完,就输出结果
if x == 9 and y == 9:
self.print_sudoku()
result = True
# 当搜到(x,9)时,说明这一行已经搜完了,该搜下一行了
elif y == 9:
result = self.dfs(x + 1, 1)
# 以上都不满足就搜这行的下一个数
else:
result = self.dfs(x, y + 1)
# 如果找到解,直接返回
if result:
return True
# 下一个格子1-9都找不到,说明假设不成立,就销毁已经做了的记录,就假设是下一个数
self.derecord(x, y)
# 1-9都假设完了,发现还不满足,说明上一个格子假设有问题,返回上一个格子
return False
def solve(self, puzzle_str):
"""解数独主函数"""
# 重置所有记录
self.r = [[False] * 10 for _ in range(10)]
self.c = [[False] * 10 for _ in range(10)]
self.g = [[False] * 10 for _ in range(10)]
self.sd = [[0] * 10 for _ in range(10)]
# 将字符串转换为数独数组
index = 0
for i in range(1, 10):
for j in range(1, 10):
if index < len(puzzle_str):
char = puzzle_str[index]
if char.isdigit() and char != '0':
self.sd[i][j] = int(char)
self.record(i, j)
else:
self.sd[i][j] = 0
index += 1
# 开始求解
return self.dfs(1, 1)
def solve_sudoku_print(puzzle_str):
"""求解数独并打印结果"""
solver = SudokuSolver()
if not solver.solve(puzzle_str):
print("该数独无解")
def main():
if len(sys.argv) != 2:
print("用法: python script.py <文件名>")
b='000000068900000002000400500041000000000035000050000000000800010300000700000100400';
solve_sudoku_print(b)
return
filename = sys.argv[1]
try:
with open(filename, 'r', encoding='utf-8') as file:
while True:
line = file.readline().strip()
if line == '':
break
print(f"题目: {line}")
t = time.time()
solve_sudoku_print(line)
print(f"耗时: {round(time.time()-t, 4)} s")
print("-" * 50)
except FileNotFoundError:
print(f"错误: 文件 '{filename}' 不存在")
except Exception as e:
print(f"错误: {e}")
if __name__ == "__main__":
main()
用selen求解器程序提供的最难级别例子测试,结果如下:
g++ backsudo.cpp -O3 -o back
time echo "000000000000003085001020000000507000004000100090000000500000073002010000000040009" | ./back
9 8 7 6 5 4 3 2 1
2 4 6 1 7 3 9 8 5
3 5 1 9 2 8 7 4 6
1 2 8 5 3 7 6 9 4
6 3 4 8 9 2 1 5 7
7 9 5 4 6 1 8 3 2
5 1 9 2 8 6 4 7 3
4 7 2 3 1 9 5 6 8
8 6 3 7 4 5 2 1 9
real 0m1.743s
user 0m1.740s
sys 0m0.000s
python3 pyback.txt selensudo.txt
题目: 000000000000003085001020000000507000004000100090000000500000073002010000000040009
9 8 7 6 5 4 3 2 1
2 4 6 1 7 3 9 8 5
3 5 1 9 2 8 7 4 6
1 2 8 5 3 7 6 9 4
6 3 4 8 9 2 1 5 7
7 9 5 4 6 1 8 3 2
5 1 9 2 8 6 4 7 3
4 7 2 3 1 9 5 6 8
8 6 3 7 4 5 2 1 9
耗时: 173.0466 s
pypy3/bin/pypy3 pyback.txt selensudo.txt
题目: 000000000000003085001020000000507000004000100090000000500000073002010000000040009
9 8 7 6 5 4 3 2 1
2 4 6 1 7 3 9 8 5
3 5 1 9 2 8 7 4 6
1 2 8 5 3 7 6 9 4
6 3 4 8 9 2 1 5 7
7 9 5 4 6 1 8 3 2
5 1 9 2 8 6 4 7 3
4 7 2 3 1 9 5 6 8
8 6 3 7 4 5 2 1 9
耗时: 32.0108 s
--------------------------------------------------
比较结果可见,用时差100倍,改用pypy执行python程序,快了5倍。


被折叠的 条评论
为什么被折叠?



