数独求解问题(DFS+位运算优化)

本文探讨了数独游戏的求解算法,采用深度优先搜索(DFS)结合位运算优化的方法,成功在700毫秒内解决数独谜题。通过对比优化前后的代码,展示了如何利用位运算提升算法效率。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

In the game of Sudoku, you are given a large 9 × 9 grid divided into smaller 3 × 3 subgrids. For example,

.2738..1.
.1...6735
.......29
3.5692.8.
.........
.6.1745.3
64.......
9518...7.
.8..6534.

Given some of the numbers in the grid, your goal is to determine the remaining numbers such that the numbers 1 through 9 appear exactly once in (1) each of nine 3 × 3 subgrids, (2) each of the nine rows, and (3) each of the nine columns.

Input

The input test file will contain multiple cases. Each test case consists of a single line containing 81 characters, which represent the 81 squares of the Sudoku grid, given one row at a time. Each character is either a digit (from 1 to 9) or a period (used to indicate an unfilled square). You may assume that each puzzle in the input will have exactly one solution. The end-of-file is denoted by a single line containing the word “end”.

Output

For each test case, print a line representing the completed Sudoku puzzle.

Sample Input

.2738..1..1...6735.......293.5692.8...........6.1745.364.......9518...7..8..6534.
......52..8.4......3...9...5.1...6..2..7........3.....6...1..........7.4.......3.
end

Sample Output

527389416819426735436751829375692184194538267268174593643217958951843672782965341
416837529982465371735129468571298643293746185864351297647913852359682714128574936

思路:DFS解这道题有点极限,需要优化的东西比较复杂,参考了网上的位运算优化,终于以700ms的解决了,如果不位运算优化很难去不超时的去解这道问题

附上原超时代码,此代码修改一下应该可以过F题,单纯的求数独的题

代码:

 

​
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<queue>
#include<vector>
#include<cmath>
#include<set>
#include<stack>
#include<map> 
#define MAX 10005

typedef long long ll;

using namespace std;
 
int cnt,flag;
int Map[10][10],vistrow[10][10],vistcol[10][10],vistkaui[10][10][10];
struct node
{
	int x,y;
}a[100];
 
void DFS(int x)
{
	if(x == cnt)
	{
		flag = 1;
		return;
	}
	int I = a[x].x;
	int J = a[x].y;
	for(int i = 1; i < 10; i++)
	{
		if(!vistrow[I][i] && !vistcol[J][i] && !vistkaui[I/3][J/3][i])
		{
			Map[I][J] = i;
			vistrow[I][i] = 1;
			vistcol[J][i] = 1;
			vistkaui[I/3][J/3][i] = 1;
			DFS(x+1);
			if(!flag)
			{
				Map[I][J] = '.';
				vistrow[I][i] = 0;
				vistcol[J][i] = 0;
				vistkaui[I/3][J/3][i] = 0;
			}
		}
	}
}
 
int main()
{
	int T;
	
	while(1)
	{
		memset(vistrow,0,sizeof(vistrow));
		memset(vistcol,0,sizeof(vistcol));
		memset(vistkaui,0,sizeof(vistkaui));
 
		cnt = 0;
		flag = 0;
		
		for(int i = 0; i < 9; i++)
		{
			
			
			for(int j = 0; j < 9; j++)
			{
			    scanf("%c",Map[i][j]);
 
				if(Map[i][j] == '.')
				{
					a[cnt].x = i;
					a[cnt++].y = j;
				}
				else
				{
					vistrow[i][Map[i][j]-'] = 1;
					vistcol[j][Map[i][j]] = 1;
					vistkaui[i/3][j/3][Map[i][j]] = 1;
				}
			}
		}
		DFS(0);
		for(int i = 0; i < 9; i++)
			for(int j = 0; j < 9; j++)
			{
				if(j == 8)
					printf("%c\n",Map[i][j]);
				else
					printf("%c",Map[i][j]);
			}
	}
	return 0;
}

​

AC代码:

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<queue>
#include<vector>
#include<cmath>
#include<set>
#include<stack>
#include<map> 
#define MAX 10005

using namespace std;
char Map[10][10];
int vistrow[10],vistcol[10];
int grid[10],rec[512],num[512];

inline int g(int x,int y) 
{
    return (x/3)*3+y/3;
}
inline void flip(int x,int y,int to) 
{
    vistrow[x]^=1<<to;
    vistcol[y]^=1<<to;
    grid[g(x,y)]^=1<<to;
}
bool DFS(int x) 
{
    if(x==0) return 1;
    int minn=10,xx,yy;
    for(int i=0;i<9;i++) {
        for(int j=0;j<9;j++) 
		{
            if(Map[i][j]=='.') 
			{
                int val=vistrow[i]&vistcol[j]&grid[g(i,j)];
                if(!val) return 0;
                if(rec[val]<minn) {
                    minn=rec[val],xx=i,yy=j;
                }
            }
        }
    }
    int val=vistrow[xx]&vistcol[yy]&grid[g(xx,yy)];
    for(;val;val-=val&-val) {
        int to=num[val&-val];
        Map[xx][yy]=to+'1';
        flip(xx,yy,to);
        if(DFS(x-1)) return 1;
        flip(xx,yy,to);
        Map[xx][yy]='.';
    }
    return 0;
}
int main() {
    for(int i=0;i<1<<9;i++) {
        for(int j=i;j;j-=j&-j)
            rec[i]++;
    }
    for(int i=0;i<9;i++) {
        num[1<<i]=i;
    }
    char s[100];
    while(~scanf("%s",s)&&s[0]!='e') {
        for(int i=0;i<9;i++) 
		vistrow[i]=vistcol[i]=grid[i]=(1<<9)-1;
        int tot=0;
        for(int i=0;i<9;i++) {
            for(int j=0;j<9;j++) {
                Map[i][j]=s[i*9+j];
                if(Map[i][j]!='.') flip(i,j,Map[i][j]-'1');
                else ++tot;
            }
        }
        DFS(tot);
        for(int i=0;i<9;i++)
            for(int j=0;j<9;j++)
                printf("%c",Map[i][j]);

        printf("\n");
    }
    return 0;
}

 

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

black-hole6

你的鼓励将是我创作的动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值