upc数独#dfs

本文介绍了一种基于深度优先搜索的数独求解算法。通过使用三个布尔型二维数组来跟踪每一行、每一列和每个小方格内已填数字的状态,确保数独规则得到遵循。文章详细解释了如何遍历数独矩阵,填充缺失数字,并在找到解决方案时立即返回。此外,还讨论了如何在回溯过程中撤销选择,以便尝试其他可能的数字。

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

问题 B: 数独
时间限制: 1 Sec 内存限制: 128 MB

题目描述
这个游戏只有一个规则:
将格子填满使得每一行,每一列,和每一个小的九宫格,恰好包含1-9这9个数字

正是由于规则简单而又变化多端,数独一时间风靡全球。
现在,我们希望你能编写一个程序解决数独问题。

输入
输入数据一共9行,每行有9个字符。
输入数据描述了一个待解决的数独,其中,“?”表示数独中的空缺。
我们的输入数据总保证有唯一解。

输出
输出一共9行,每行9个数字,表示你的答案。
样例输入 Copy
5???7??6
?6???5?4
?834???
???182?4?
??1???9??
?7?369???
???543?
1?5???9?
7??2???1
样例输出 Copy
514927386
967831524
283456179
659182743
321574968
478369215
892615437
135748692
746293851

思路:
数独要求每一行、每一列、每一个3*3方阵内的数字不重复
所以我们把方阵分成9个小的方阵,并依次编号
我们需要判断行和列的重复,定义两个bool类型的二维数组
当这一行或这一列有数字或者填好数字后,标记为true
//例如第一行第三列填入数字2
bool p[ ][ ] , l[ ][ ];
p [1][2] = l[3][2] = true;
分成的9个小方阵,每过3列,方阵的序号+1,每过三行,方阵的序号+3
于是可以推出表达式:小方阵序号 = (行数-1) / 3 * 3+(列数-1) / 3+1
因为3的整数倍数/3 得到的答案会比原小方阵序号大1,所以行列数需要-1
最后dfs查找判断即可
注意数字与字符之间的转换

int sd[11][11];//数独方阵
bool p[11][11],l[11][11],fz[11][11];
//行,列,序号小方阵

void _out()//输出
{
	for(int i=1;i<=9;i++)
	{
		for(int j=1;j<=9;j++)
			printf("%d",sd[i][j]);
		printf("\n");
		//每一行输出完成,换行 
	}
	exit(0);
	//用return的话不会退出dfs函数,会增加运算量 
}

void dfs(int x,int y)//深搜,传参行列
{
	if(sd[x][y] != 0)//表示已经标记过,这个位置有数字
	{
		if(x == 9 && y == 9)	_out();
		//行和列都已经填好数字,输出即可
 		else if(y == 9)	dfs(x+1,1);
 		//列数等于9,说明这一行已经填好数字,搜索下一行
		else	dfs(x,y+1);//搜索下一列
	}
	else//没有标记过,需要填数字
	{
		for(int i=1;i<=9;i++)
		{
			if(!p[x][i] && !l[y][i] && (!fz[(x-1)/3*3+(y-1)/3+1][i]))
			//判断行列和小方阵中是否被标记
			{
				sd[x][y] = i;
				p[x][i] = true;
				l[y][i] = true;
				fz[(x-1)/3*3+(y-1)/3+1][i] = true;
				//填上数之后标记一下
				if(x == 9 && y == 9)	_out();
				else if(y == 9)	dfs(x+1,1);
				else	dfs(x,y+1);
				sd[x][y] = 0;//恢复标记,回溯
				p[x][i] = false;
				l[y][i] = false;
				fz[(x-1)/3*3+(y-1)/3+1][i] = false;
				//恢复标记,回溯
			}
		}
	}
}


int main()
{
	for(int i=1;i<=9;i++)//枚举行 
	{
		for(int j=1;j<=9;j++)//枚举列 
		{
			char s;	int t;	cin >> s;
			t = s-48;
			if(t <= 9)
            {
            	p[i][t] = true;
            	l[j][t] = true;
            	fz[(i-1)/3*3+(j-1)/3+1][t] = true;
            	//填充的不是?的话,表示原来有数字了,打上标记 
            	sd[i][j] = t;//放到方阵中 
			}
		}
	}
	dfs(1,1);
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

你数过天上的星星吗

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

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

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

打赏作者

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

抵扣说明:

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

余额充值