UVA10957 So Doku Checker
题意简述
有若干个数据,每次会给你一个 \(9 \times 9\) 的数独,你需要补全这个数独。其中 \(1\) ~ \(9\) 表示已经确定的数,\(0\) 代表不确定的数,也就是你要填的数。(数独规则请自行百度)
如果输入的数独已经不符合规则,输出“Illegal”;如果有唯一解,输出“Unique”;如果有多组解,输出“Ambiguous”;如果无解,输出“Impossible”。(注意是 illegal,只是第一个 i 大写了)
题目分析
对于数独一类的问题以及如此小的数据范围(虽然没有说有多少组数据),考虑暴力搜索。
首先特判 Illegal 的情况,对每一行每一列每一个宫格开个桶检查一遍,不符合就直接输出。
然后从 \((1,1)\) 开始搜索,每次搜索到一个点就判断这一列这一行和这一宫格已经有了哪些数,再选择没出现过的数往下搜索。如果没有就返回。
到了 \((9,9)\) 如果符合要求,就说明有一个解。最后判断解的个数就可以了。
由于有数独的规则,搜索的很大一部分其实都被剪枝掉了,所以时间是可以接受的。
注意几点:
-
输出格式要按题目要求(其实看样例输出就懂了)。
-
如果到了每一行的尽头,就要到下一行开始搜索(其实搜索顺序没所谓,我这里是一行一行搜)。
-
如果这个数原本是空的(即为0),那么返回的时候也要赋回0。
-
每次检查要把桶清零,或者定义局部变量。
代码
#include<bits/stdc++.h>
using namespace std;
namespace my_std{
#define ll long long
#define bl bool
#define pf printf
#define pc putchar
#define fr(i,x,y) for(register ll i=(x);i<=(y);i++)
#define il inline
il ll read(){
ll sum=0,f=1;
char ch=0;
while(!isdigit(ch)){
if(ch=='-') f=-1;
ch=getchar();
}
while(isdigit(ch)){
sum=sum*10+(ch^48);
ch=getchar();
}
return sum*f;
}
}
using namespace my_std;
ll a[11][11],cnt=0,ans=0;
bl ck[11],pd;
void dfs(ll x,ll y){
if(a[x][y]){//如果已经有值
if(x==9&&y==9) ans++;
else if(y==9) dfs(x+1,1);
else dfs(x,y+1);
return;
}
bl ckk[11];
memset(ckk,0,sizeof(ckk));
fr(i,1,9){//检查行/列
ckk[a[x][i]]=1;
ckk[a[i][y]]=1;
}
fr(i,3*((x-1)/3)+1,3*((x-1)/3)+3) fr(j,3*((y-1)/3)+1,3*((y-1)/3)+3) ckk[a[i][j]]=1;//检查宫格
fr(i,1,9){
if(!ckk[i]){//判断可以填哪些数
a[x][y]=i;
if(x==9&&y==9) ans++;
else if(y==9) dfs(x+1,1);
else dfs(x,y+1);
a[x][y]=0;//赋回0
}
}
}
int main(){
while(~scanf("%lld",&a[1][1])){
ans=0;
cnt++;
fr(i,1,9) fr(j,1,9) if(i!=1||j!=1) a[i][j]=read();
pd=0;
fr(i,1,9){//检查每一行
memset(ck,0,sizeof(ck));
fr(j,1,9){
if(ck[a[i][j]]&&a[i][j]) pd=1;
ck[a[i][j]]=1;
}
}
fr(i,1,9){//检查每一列
memset(ck,0,sizeof(ck));
fr(j,1,9){
if(ck[a[j][i]]&&a[j][i]) pd=1;
ck[a[j][i]]=1;
}
}
for(ll i=1;i<=9;i+=3){//检查每一宫格
for(ll j=1;j<=9;j+=3){
memset(ck,0,sizeof(ck));
fr(ii,i,i+2){
fr(jj,j,j+2){
if(ck[a[ii][jj]]&&a[ii][jj]) pd=1;
ck[a[ii][jj]]=1;
}
}
}
}
if(pd){
pf("Case %lld: Illegal.\n",cnt);
continue;
}
dfs(1,1);
if(!ans) pf("Case %lld: Impossible.\n",cnt);
else if(ans==1) pf("Case %lld: Unique.\n",cnt);
else pf("Case %lld: Ambiguous.\n",cnt);
}
}