同样算法的DFS求解数独C和Python程序用时比较

网上看到一个特别简短的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倍。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值