AcWing 166. 数独

数独是一种传统益智游戏,你需要把一个 9×9 的数独补充完整,使得图中每行、每列、每个 3×3 的九宫格内数字 1∼9

均恰好出现一次。

请编写一个程序填写数独。
输入格式

输入包含多组测试用例。

每个测试用例占一行,包含 81
个字符,代表数独的 81

个格内数据(顺序总体由上到下,同行由左到右)。

每个字符都是一个数字(1−9

)或一个 .(表示尚未填充)。

您可以假设输入中的每个谜题都只有一个解决方案。

文件结尾处为包含单词 end 的单行,表示输入结束。
输出格式

每个测试用例,输出一行数据,代表填充完全后的数独。
输入样例:

4…8.5.3…7…2…6…8.4…1…6.3.7.5…2…1.4…
…52…8.4…3…9…5.1…6…2…7…3…6…1…7.4…3.
end

输出样例:

417369825632158947958724316825437169791586432346912758289643571573291684164875293
416837529982465371735129468571298643293746185864351297647913852359682714128574936

转链接https://www.acwing.com/problem/content/168/
题解:

#include<bits/stdc++.h>
using namespace std;
const int N=9;

//row,col,cell分别存储每一个单元格可以存放的数,将其放到二进制位上,比如一个单元格可以存储123:0000000111 
int row[N],col[N],cell[3][3];
//打表内容 ,ones打表0-2^9-1的二进制含有1的个数
int ones[1<<N],Map[1<<N];

char str[100];
//求二进制数的第一个1,inline内联函数,主要用于减少时间 
inline int lowbit(int x){
	return x&-x;
}

//获取x,y单元格可以选择的数
inline int get (int x,int y){
	return row[x]&col[y]&cell[x/3][y/3];
}

void init(){
	//row[],col[],cell[][]每一个初始化都应为111111111,即每个数都可选
	for(int i=0;i<N;i++)
	row[i]=col[i]=(1<<N)-1;
	for(int i=0;i<3;i++)
	for(int j=0;j<3;j++)
	 cell[i][j]=(1<<N)-1;
}

//递归
bool dfs(int cnt){
	if(cnt==0)
	return true;
	int minv=10,x,y;
	//获取能填个数最少的单元格 
	for(int i=0;i<N;i++)
	for(int j=0;j<N;j++){
		if(str[i*9+j]=='.'){
			if(ones[get(i,j)]<minv){
				minv=ones[get(i,j)];
				x=i,y=j;
			}
		}
	}
	for(int i=get(x,y);i>0;i-=lowbit(i)){
		
	int t=Map[lowbit(i)];
	str[x*9+y]=t+'1';
	row[x]-=1<<t;
	col[y]-=1<<t;
	cell[x/3][y/3]-=1<<t;
	if(dfs(cnt-1)) return true;
	row[x]+=1<<t;
	col[y]+=1<<t;
	cell[x/3][y/3]+=1<<t;
	str[x*9+y]='.';
}
	return false;
} 
int main(){
	//map
	for(int i=0;i<N;i++)
    Map[1<<i]=i;
	//打表ones
	for(int i=0;i<1<<N;i++){
		int s=0;
		for(int j=i;j>0;j-=lowbit(j))
		s++;
		ones[i]=s;
	}
	
	//读取数独字符串 
	 while(~scanf("%s",str)&&str[0]!='e'){
	 	//cnt记录需写的个数 
	int cnt=0;
		 init(); 
		 for(int i=0,k=0;i<N;i++)
		 for(int j=0;j<N;j++,k++){
		 	if(str[k]!='.'){
		 		int t=str[k]-'1';
		 		row[i]-=1<<t;
		 		col[j]-=1<<t;
		 		cell[i/3][j/3]-=1<<t;
			 }
			 else cnt++;
		 }
		 
		 dfs(cnt);
		 cout<<str<<endl; 
	 }
	 return 0;
} 

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值