YbtOJ——深度搜索【例题2】数独游戏

本文分享了一种独特的数独解题方法,利用三个二维数组进行行、列和宫的判重,结合深度优先搜索(DFS)。作者介绍了判重规则、代码实现以及如何初始化判重数组。通过这个方法,简化了解题步骤并提高了效率。

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

B. 【例题2】数独游戏

题目

在这里插入图片描述

题解

经过不断地debug,终于用自己的方法做出这题了。
我的方法跟书上的不同,自认为更简单些。

用三个二维数组分别记录每一行、列、宫中是否出现1~9,即判重,来进行剪枝。
dfs每个输入时就储存下来的空着的格子,枚举1~9并根据判重数组判断能否填入该数字。
填完所有空格后,输出并直接退出,最后别忘了初始化那三个判重数组,因为有多组数据。
若点 ( x , y ) (x,y) x,y的数为 t t t,三个判重的数组可以这样写:

fx[x][t]=1;//行
fy[y][t]=1;//列
fg[(x-1)/3*3+(y-1)/3+1][t]=1;//宫

对于宫判重,我们将宫编号:
在这里插入图片描述
套用我想出的小公式: ( x − 1 ) / 3 ∗ 3 + ( y − 1 ) / 3 + 1 (x-1)/3*3+(y-1)/3+1 (x1)/33+(y1)/3+1(证明略)就可求出每个点属于的宫。

代码

#include<iostream>
#include<cmath>
#include<cstring>
using namespace std;
int a[100][100],b[100][2],c[100],fx[10][10],fy[10][10],fg[10][10],n;
string s;
bool check(int x,int y,int t)//判断是否可填该数
{
	if(fx[x][t]||fy[y][t]||fg[(x-1)/3*3+(y-1)/3+1][t]) return false;
	else //无重复,即可填,判重数组标记为一
	{
		fx[x][t]=1;
		fy[y][t]=1;
		fg[(x-1)/3*3+(y-1)/3+1][t]=1;
		return true;
	}
}
void back(int x,int y,int t)//回溯,还原信息
{
	fx[x][t]=0;
	fy[y][t]=0;
	fg[(x-1)/3*3+(y-1)/3+1][t]=0;
}
bool dfs(int dep)
{
	if(dep>n)
	{
		n=0;
		for(int i=1; i<=9; i++)
		{
			for(int j=1; j<=9; j++)
			{
				if(a[i][j]) cout<<a[i][j];
				else cout<<c[++n];
			}
		}
		cout<<endl;
		return true;//返回真,以便快速退出
	}
	else
	{
		int x=b[dep][0],y=b[dep][1];
		for(int i=1; i<=9; i++)
		{
			if(check(x,y,i))
			{
				c[dep]=i;//另存空格填的数
				if(dfs(dep+1)) return true;//直接退出
				back(x,y,i);
			}
		}
	}
	return false;
}
int main()
{
	getline(cin,s);
	while(s!="end")
	{
		for(int i=0; i<81; i++)
		{
			int xt=i/9,yt=i%9;
			if(s[i]=='.')
			{
				a[xt+1][yt+1]=0;
				b[++n][0]=xt+1,b[n][1]=yt+1;//存下空格坐标
			}
			else
			{
				a[xt+1][yt+1]=s[i]-48;
				fx[xt+1][s[i]-48]=1;
				fy[yt+1][s[i]-48]=1;
				fg[(xt/3*3+yt/3+1)][s[i]-48]=1;
			}
		}
		dfs(1);
		n=0;
		memset(fx,0,sizeof(fx));
		memset(fy,0,sizeof(fy));
		memset(fg,0,sizeof(fg));
		//初始化👆,很重要
		getline(cin,s);
	}
}
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值