给出一个 13 × 13 13\times 13 13×13的矩阵
(实际是 9 × 9 9\times 9 9×9的,但是旁边有多余的
输入),问这个数独是否符合条件
条件:每一列
,每一行
,每一个九宫格
,都有数字 1 − 9 1-9 1−9 不能有重复
的数字
样例中只有.
和0~9
有用,其他可以看做多余的
+---+---+---+
|52.|...|.81|
|.39|58.|...|
|.8.|.9.|...|
+---+---+---+
|24.|...|1.3|
|1..|43.|86.|
|.63|..7|.24|
+---+---+---+
|...|1.9|35.|
|..8|.74|6..|
|31.|86.|7.9|
+---+---+---+
OK
样例1解释:这个数独没有重复的,所以输出OK
+---+---+---+
|3..|6..|..4|
|4.9|8.1|..7|
|..7|.49|6..|
+---+---+---+
|946|157|8.2|
|.2.|3..|745|
|.7.|28.|...|
+---+---+---+
|...|4..|..5|
|8.5|.6.|.2.|
|734|..8|5..|
+---+---+---+
GRESKA
样例2解释:第 9 9 9 列数字 5 5 5 出现了 2 2 2 次,且右下角的一个九宫格中的数字 5 5 5 出现了 2 2 2 次
+---+---+---+
|5..|98.|67.|
|6..|...|.31|
|.2.|613|.4.|
+---+---+---+
|.96|8.2|1.7|
|.28|..5|.9.|
|7.3|19.|6..|
+---+---+---+
|962|.7.|.1.|
|1.5|...|76.|
|.7.|5..|9..|
+---+---+---+
GRESKA
样例3解释:第 2 2 2 列数字 2 2 2 出现了 2 2 2 次,且第 7 7 7 列数字 6 6 6 出现了
可以使用桶排序去重
的方法来进行预处理
如果有数的个数>1
,就可以证明这个数独并不合法
详见:去重算法(桶排序去重)
只需以起始坐标为原点,遍历一个 3 × 3 3\times 3 3×3的正方形即可
其中的九宫格起点
,就是起始坐标
在数独里起始坐标有(1,1),(1,4),(1,7),(4,1),(4,4),(4,7),(7,1),(7,4),(7,7)
#include
using namespace std;
char a[15][15];
int c[15][15],x=1,y=0,vis[15]={},vis2[15]={},vis3[15]={};//vis[] 是统计横排有无重复的数组,vis2[] 是统计数列有无重复的数组,vis3[] 是统计九宫格内有无重复的数组
int jgg(int x,int y){//九宫格左上角作为起始的数的坐标
for(int i=0;i<=2;i++){
for(int j=0;j<=2;j++){//如实在没看懂,可看上图 ↑
vis3[c[x+i][y+j]]++;//统计c[x][y],c[x][y+1],c[x][y+2],c[x+1][y],c[x+1][y+1],c[x+1][y+2],c[x+2][y],c[x+2][y+1],c[x+2][y+2]
}//遍历统计九宫格内有无重复的数出现的预处理
}
for(int i=1;i<=9;i++){
if(vis3[i]>1) return 1;//统计九宫格内是否有重复的数出现,如果有就可以跳到第33行
}
memset(vis3,0,sizeof(vis3));//将数组全部归0,避免下一次重复计算
return 0;//函数正常运行,跳到第30行
}
int pass(){//检查数独是否成立的函数
for(int i=1;i<=9;i++){
for(int j=1;j<=9;j++){
vis[c[i][j]]++;//遍历统计竖列内有无重复的数出现的预处理
vis2[c[j][i]]++;//遍历统计横排内有无重复的数出现的预处理
}
for(int j=1;j<=9;j++){
if(vis[j]>1) return 1;//如果有重复的,直接返回1
if(vis2[j]>1) return 1;//同上
}
memset(vis,0,sizeof(vis));//将数组全部归0,避免下一次重复计算
memset(vis2,0,sizeof(vis2));//同上
}
if(jgg(1,1)==0&&jgg(1,4)==0&&jgg(1,7)==0&&jgg(4,1)==0&&jgg(4,4)==0&&jgg(4,7)==0&&jgg(7,1)==0&&jgg(7,4)==0&&jgg(7,7)==0){//九宫格所有的起始坐标
return 0;//返回0代表成立
}
else{
return 1;//有某一个九宫格内有重复的,数独不成立,返回答案1
}
}
int main(){
freopen("sudoku.in","r",stdin);
freopen("sudoku.out","w",stdout);
for(int i=1;i<=13;i++){
for(int j=1;j<=13;j++){
cin>>a[i][j];
if(a[i][j]-'0'<=9&&a[i][j]-'0'>=0){
c[x][++y]=a[i][j]-'0';//因为输入格式的问题,所以用x,y来存储坐标
}
if(a[i][j]=='.'){
c[x][++y]=0;
}
}
y=0;//将坐标赋值为0
x++;//每一次行数+1
if(a[i][2]=='-') x--;//如果输入的是空行,那么x应该-1
}
if(pass()==0){//如果数独成立,输出"OK"
cout<<"OK";
return 0;
}
else{
cout<<"GRESKA";//否则,输出"GRESKA"
return 0;
}
return 0;
}