专栏文章

题解:B4279 [蓝桥杯青少年组国赛 2023] 数独填数

B4279题解参与者 1已保存评论 0

文章操作

快速查看文章及其快照的属性,并进行相关操作。

当前评论
0 条
当前快照
1 份
快照标识符
@mipa26om
此快照首次捕获于
2025/12/03 08:37
3 个月前
此快照最后确认于
2025/12/03 08:37
3 个月前
查看原文

DFS

这个题DFS题解已经很多了,所以这篇题解的侧重点会在我认为比较巧妙的细节上。

思路: DFS

遍历每一个格子,若格子为空,遍历每一种符合要求的数,数独填满后结束遍历
DFS 不用我说了吧,我来讲一些细节:
一、判断一个数是否符合要求:
要求有 33 点:
  1. 每一行包含 1199 且不重复;
  2. 每一列包含 1199 且不重复;
  3. 每一个 3×33 \times 3 的大格子包含 1199 且不重复。
怎么这么八皇后啊。
前两点好解决,开个数组记一下。
第三点有些麻烦,我看很多大佬打了个表。其实不用那么麻烦,建一个 3×33 \times 3 的数组存大格子,设小格子下标为 xxyy,调用的时候用 (x+2)÷3(x + 2) \div 3(y+2)÷3(y + 2) \div 3 作为大格子下标就行了。
二、判断数独是否填满:
很多人用扫完数独作为 DFS 的结束条件,其实,只要数独填满了就可以结束了。
问题又来了,怎么判断数独是否填满了呢?
我们可以建一个变量,每填上一个格子就让他加 11(包括输入),加到 8181 就代表填满了。

代码:(仅供参考)

讲思路我本来不想发代码的
CPP
#include <bits/stdc++.h>
using namespace std;
bool h[10][10];
bool l[10][10];
bool g[4][4][10];//大格子
int sd[10][10];
int cnt;//填了几个格子
bool ans=0;
void dfs(int x,int y){
	if(cnt==81){//填满了就结束
		for(int i=1;i<=9;i++){
			for(int j=1;j<=9;j++){
				cout<<sd[i][j];
			}
			cout<<"\n";
		}
		ans=1;
		return;
	}
	if(sd[x][y]!=0){
		if(y==9) dfs(x+1,1);
		else dfs(x,y+1);
		return;
	} 
	for(int j=1;j<=9;j++){
		if(!h[x][j]&&!l[y][j]&&!g[(x+2)/3][(y+2)/3][j]){
			h[x][j]=1,l[y][j]=1,g[(x+2)/3][(y+2)/3][j]=1,sd[x][y]=j,cnt++;
			dfs(x,y);
			if(ans)return;
			h[x][j]=0,l[y][j]=0,g[(x+2)/3][(y+2)/3][j]=0,sd[x][y]=0,cnt--;//回溯
		}
	}
}
int main() {
	char x;
	for(int i=1; i<=9; i++) {
		for(int j=1; j<=9; j++) {
			cin>>x; 
			if(x>='0'&&x<='9'){
				int xx=x-'0';
				sd[i][j]=xx;
				h[i][xx]=1;
				l[j][xx]=1;
				g[(i+2)/3][(j+2)/3][xx]=1;//上面提到过的公式
				cnt++;//一定一定要有
			}
		}
	}
	dfs(1,1);
  return 0;//完结撒花
}

评论

0 条评论,欢迎与作者交流。

正在加载评论...