YBTOJ 数独游戏

题面

image
image

题目分析:

选择一个当前可选的数最小的位置,依次填入各个可能填入的数。

考虑怎么实现:
为了快速地得到每个位置可以选择的位置,可以将当前树所在的行、列、九宫格的填入状态压入一个二进制中储存。

Code

#include<bits/stdc++.h>
using namespace std;
const int INF=1e9+7;
int cnt[10004];//cnt[i]存储每个9位二进制数i能被取几次lowbit,即当前状态i先还有几个1,即当前状态还有几个数可选 
int num[10004];//num[i]用二进制表示每一个数,lowbit(i)中i位于第几位,i代表第几个数 
//num和cnt的值事先被预处理好,不会在过程中被改变 
int tot;//表示开始时未被填入数字的格子数有多少 
int mapp[10][10];//存储每个位置所存的数字 
int a[10],b[10],c[10];//a,b,c分别存储行、列、九宫格中的每个数是否可选的状态(压成二进制表示) 
char s[82];
int f(int x,int y){return x/3*3+y/3;}//f函数可以快速得到每个点所在九宫格的编号 
int lowbit[5005];
void change(int x,int y,int v)
{	
	a[x]^=(1<<v);
	b[y]^=(1<<v);
	c[f(x,y)]^=(1<<v); 
}//把v对应的位数更改一下(这里用xor更改,因此可以完成两种修改:不可选->可选 or 可选->不可选
bool dfs(int idx)
{
	if(idx==tot+1) return true;
	int Minv=INF,x=0,y=0;
	for(int i=0;i<9;++i)																								
	{
		for(int j=0;j<9;++j)
		{
			if(mapp[i][j]!=-1) continue;	
			int state=a[i]&b[j]&c[f(i,j)];
			if(cnt[state]==0) return false;
			if(cnt[state]<Minv) Minv=cnt[state],x=i,y=j;
		}
	}
	int state=a[x]&b[y]&c[f(x,y)];
	for(;state;state-=lowbit[state])
	{
		int val=num[lowbit[state]];
		mapp[x][y]=val;
		change(x,y,val);
		if(dfs(idx+1)) return true;
		change(x,y,val);
		mapp[x][y]=-1;	
	}
	return false;
}
void work()
{
	tot=0;
	for(int i=0;i<9;++i) a[i]=b[i]=c[i]=(1<<9)-1;
	for(int i=0;i<9;++i)
	{
		for(int j=0;j<9;++j)
		{
			char ch=s[i*9+j];
			if(ch=='.') tot++,mapp[i][j]=-1;
			else mapp[i][j]=ch-'1',change(i,j,mapp[i][j]);
		}
	}
	dfs(1);
	for(int i=0;i<9;++i) 
		for(int j=0;j<9;++j)
			printf("%d",mapp[i][j]+1);
	printf("\n");	
}
int main()
{
	for(int i=0;i<(1<<9);++i) lowbit[i]=i&(-i);
	for(int i=0;i<9;++i) num[1<<i]=i; 
	for(int i=0;i<(1<<9);++i)
		for(int j=i;j;j-=lowbit[j])
			cnt[i]++;
	while(scanf("%s",s),s[0]!='e') work();
	return 0;	
}
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值