P9903 [COCI 2023/2024 #1] Sudoku【数独】

文章目录

    • 题意
      • 输入格式&输入样例
        • 1.样例输入1
        • 2.样例输出1
        • 3.样例输入2
        • 4.样例输出2
        • 5.样例输入3
        • 6.样例输出3
    • 具体code & 解释
      • 1.如何统计每个数的个数
      • 2.如何遍历九宫格
    • code↓

题意

给出一个 13 × 13 13\times 13 13×13矩阵(实际是 9 × 9 9\times 9 9×9的,但是旁边有多余的输入),问这个数独是否符合条件

条件:每一,每一,每一个九宫格,都有数字 1 − 9 1-9 19 不能有重复的数字

输入格式&输入样例

样例中只有.0~9有用,其他可以看做多余的

1.样例输入1
+---+---+---+
|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|
+---+---+---+
2.样例输出1
OK

样例1解释:这个数独没有重复的,所以输出OK

3.样例输入2
+---+---+---+
|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..|
+---+---+---+
4.样例输出2
GRESKA

样例2解释:第 9 9 9 列数字 5 5 5 出现了 2 2 2 次,且右下角的一个九宫格中的数字 5 5 5 出现了 2 2 2

5.样例输入3
+---+---+---+
|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..|
+---+---+---+
6.样例输出3
GRESKA

样例3解释:第 2 2 2 列数字 2 2 2 出现了 2 2 2 次,且第 7 7 7 列数字 6 6 6 出现了

具体code & 解释

1.如何统计每个数的个数

可以使用桶排序去重的方法来进行预处理

如果有数的个数>1,就可以证明这个数独并不合法

详见:去重算法(桶排序去重)

2.如何遍历九宫格

只需以起始坐标为原点,遍历一个 3 × 3 3\times 3 3×3的正方形即可
P9903 [COCI 2023/2024 #1] Sudoku【数独】_第1张图片
其中的九宫格起点,就是起始坐标

在数独里起始坐标有(1,1),(1,4),(1,7),(4,1),(4,4),(4,7),(7,1),(7,4),(7,7)

code↓

#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;
}

你可能感兴趣的:(c++_topic,算法,c++,开发语言)