2021.11.2测试-T1数独
Posted gyc#66ccff
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了2021.11.2测试-T1数独相关的知识,希望对你有一定的参考价值。
数 独
【问题描述】
数独是一个有趣的游戏。你需要在一个 9 ×9 的矩阵中的每个格子中填入 1 ~
9 的数字,使得没有两个相同的数字填入同一行、同一列或同一个九宫格中。
整个矩阵被划分为 9 个九宫格,若两个格子同时在最左三列、最右三列或中
间三列,且同时在最左三行、最右三行或中间三行,则这两个格子在同一九宫格
中。
如果两个相同的数同行、同列或同九宫格,则构成一对冲突。如下列状态中,
两个 1 在同一行中,两个 2 在同一列中,两个 3 在同一九宫格中,分别是三对冲
突;但两个 4 不是一对冲突。
现在有一个数独的初始状态,出题人想对其进行一些修改和询问操作。需要
注意:在操作时,初始状态中的数也可以被删除或者合并时被替换。
1. 向目前状态中的指定位置填入一个数:但有可能这个位置已经有一个数
了,此时你需要输出一行 Error!,然后不进行这次修改操作;在指定的
这个位置没有数的情况下,这个数已经与之前存在的在同一行、列或九
宫格中的数构成冲突,此时,你需要按照行、列、九宫格的顺序,找到
第一种冲突的情况,输出一行 Error:row! , Error:column!或
Error:square!,然后不进行这次修改操作;否则,你需要输出 OK!,
并在指定位置填入该数。
2. 删除目前状态中的一个位置上的数:若这个位置没有数字,此时你需要
输出一行 Error!,然后不进行任何操作;否则你需要输出一行 OK!,并
将该位置的数删除。
3. 查询目前状态中的某个位置能填入多少种数字;若被查询的位置已经有
数字了,你需要输出一行 Error!;否则,输出一行一个整数n 表示能填
入的数字个数,随后 n 行每行一个整数,按照从小到大的顺序输出能填
入的数字。
4. 将之前的第 i 次操作后的数独状态和第j 次操作后的数独状态进行合并,
作为当前状态。需要注意:对于所有的 5 种操作,包括但不限于出现
Error!或是没有进行任何修改,均被算作一次操作。合并时以行为第一
关键字,列为第二关键字的顺序依次考虑每个格子,若第 i 次操作后的
数独状态中该位置有数且不会与之前冲突则优先填入;否则,在不会与
之前冲突的情况下,填入第 j 次操作后的数独状态中该位置的数。若均
没有数字或均与本次合并中已填入的数字冲突,则不填入任何数。输出
一行,包含空格隔开的两个整数,表示最终的结果中有多少数字来自第
i 次操作后的数独状态中,多少来自第j 次操作后的数独状态中。
5. 查询整个数独的状态,你需要使用方阵格式将整个数独目前的状态输出。
方阵格式是一个 19×19 的二维字符数组,具体格式如下,其中用0 表示
该位置还未填入数字。
+-+-+-+-+-+-+-+-+-+
|0|0|0|0|0|0|0|0|0|
+-+-+-+-+-+-+-+-+-+
|0|0|0|0|0|0|0|0|0|
+-+-+-+-+-+-+-+-+-+
|0|0|0|0|0|0|0|0|0|
+-+-+-+-+-+-+-+-+-+
|0|0|0|0|0|0|0|0|0|
+-+-+-+-+-+-+-+-+-+
|0|0|0|0|0|0|0|0|0|
+-+-+-+-+-+-+-+-+-+
|5|7|0|0|0|0|0|0|0|
+-+-+-+-+-+-+-+-+-+
|0|0|0|0|7|1|0|0|0|
+-+-+-+-+-+-+-+-+-+
|0|0|0|0|0|0|0|0|0|
+-+-+-+-+-+-+-+-+-+
|9|8|7|6|5|4|3|2|1|
+-+-+-+-+-+-+-+-+-+
【输入格式】
输入的前 19 行为一个二维字符数组,为数独的初始状态的方阵格式。
随后一行一个整数 T 表示操作的次数。
随后 T 行,每行为下列形式:
Insert x y k,表示在(x , y )位置插入数 k 。
Delete x y,表示删除(x , y )位置的数。
Query x y,表示查询(x , y )位置能填入且不会出现冲突的数。
Merge i j,表示合并第 i 次操作后的状态和第j 次操作后的状态。
Print,表示查询整个数独的状态。
其中 x 表示行数,从上到下分别为 1 到 9,y 表示列数,从左到右分别为 1
到 9 。
【输出格式】
对于每个操作,你需要按照题目述进行对应的输出。
【样例输入输出1】
+-+-+-+-+-+-+-+-+-+
|0|0|0|0|0|0|0|0|0|
+-+-+-+-+-+-+-+-+-+
|0|0|0|0|0|0|0|0|0|
+-+-+-+-+-+-+-+-+-+
|0|0|0|0|0|0|0|0|0|
+-+-+-+-+-+-+-+-+-+
|0|0|0|0|0|0|0|0|0|
+-+-+-+-+-+-+-+-+-+
|0|0|0|0|0|0|0|0|0|
+-+-+-+-+-+-+-+-+-+
|5|7|0|0|0|0|0|0|0|
+-+-+-+-+-+-+-+-+-+
|0|0|0|0|7|1|0|0|0|
+-+-+-+-+-+-+-+-+-+
|0|0|0|0|0|0|0|0|0|
+-+-+-+-+-+-+-+-+-+
|9|8|7|6|5|4|3|2|1|
+-+-+-+-+-+-+-+-+-+
9
Insert 7 1 2
Insert 8 1 2
Insert 8 2 2
Query 8 9
Delete 6 1
Delete 8 1
Insert 1 1 1
Merge 6 4
Print
OK!
Error:column!
Error:square!
6
4
5
6
7
8
9
OK!
Error!
OK!
13 1
+-+-+-+-+-+-+-+-+-+
|0|0|0|0|0|0|0|0|0|
+-+-+-+-+-+-+-+-+-+
|0|0|0|0|0|0|0|0|0|
+-+-+-+-+-+-+-+-+-+
|0|0|0|0|0|0|0|0|0|
+-+-+-+-+-+-+-+-+-+
|0|0|0|0|0|0|0|0|0|
+-+-+-+-+-+-+-+-+-+
|0|0|0|0|0|0|0|0|0|
+-+-+-+-+-+-+-+-+-+
|5|7|0|0|0|0|0|0|0|
+-+-+-+-+-+-+-+-+-+
|2|0|0|0|7|1|0|0|0|
+-+-+-+-+-+-+-+-+-+
|0|0|0|0|0|0|0|0|0|
+-+-+-+-+-+-+-+-+-+
|9|8|7|6|5|4|3|2|1|
+-+-+-+-+-+-+-+-+-+
【样例输入输出2 】
+-+-+-+-+-+-+-+-+-+
|0|0|0|0|0|0|0|0|0|
+-+-+-+-+-+-+-+-+-+
|0|0|0|0|0|0|0|0|0|
+-+-+-+-+-+-+-+-+-+
|0|0|0|0|0|0|0|0|0|
+-+-+-+-+-+-+-+-+-+
|0|0|0|0|0|0|0|0|0|
+-+-+-+-+-+-+-+-+-+
|0|0|0|0|0|0|0|0|0|
+-+-+-+-+-+-+-+-+-+
|0|0|0|0|0|0|0|0|0|
+-+-+-+-+-+-+-+-+-+
|0|0|0|0|0|0|0|0|0|
+-+-+-+-+-+-+-+-+-+
|0|0|0|0|0|0|0|0|0|
+-+-+-+-+-+-+-+-+-+
|0|0|0|0|0|0|0|0|0|
+-+-+-+-+-+-+-+-+-+
84
Insert 1 1 1
Insert 1 2 1
Insert 1 3 1
Insert 1 4 1
Insert 1 5 1
Insert 1 6 1
Insert 1 7 1
Insert 1 8 1
Insert 1 9 1
Insert 2 1 1
Insert 2 2 1
Insert 2 3 1
Insert 2 4 1
Insert 2 5 1
Insert 2 6 1
Insert 2 7 1
Insert 2 8 1
Insert 2 9 1
Insert 3 1 1
Insert 3 2 1
Insert 3 3 1
Insert 3 4 1
Insert 3 5 1
Insert 3 6 1
Insert 3 7 1
Insert 3 8 1
Insert 3 9 1
Insert 4 1 1
Insert 4 2 1
Insert 4 3 1
Insert 4 4 1
Insert 4 5 1
Insert 4 6 1
Insert 4 7 1
Insert 4 8 1
Insert 4 9 1
Insert 5 1 1
Insert 5 2 1
Insert 5 3 1
Insert 5 4 1
Insert 5 5 1
Insert 5 6 1
Insert 5 7 1
Insert 5 8 1
Insert 5 9 1
Insert 6 1 1
Insert 6 2 1
Insert 6 3 1
Insert 6 4 1
Insert 6 5 1
Insert 6 6 1
Insert 6 7 1
Insert 6 8 1
Insert 6 9 1
Insert 7 1 1
Insert 7 2 1
Insert 7 3 1
Insert 7 4 1
Insert 7 5 1
Insert 7 6 1
Insert 7 7 1
Insert 7 8 1
Insert 7 9 1
Insert 8 1 1
Insert 8 2 1
Insert 8 3 1
Insert 8 4 1
Insert 8 5 1
Insert 8 6 1
Insert 8 7 1
Insert 8 8 1
Insert 8 9 1
Insert 9 1 1
Insert 9 2 1
Insert 9 3 1
Insert 9 4 1
Insert 9 5 1
Insert 9 6 1
Insert 9 7 1
Insert 9 8 1
Insert 9 9 1
Delete 1 1
Query 1 1
Print
OK!
Error:row!
Error:row!
Error:row!
Error:row!
Error:row!
Error:row!
Error:row!
Error:row!
Error:column!
Error:square!
Error:square!
OK!
Error:row!
Error:row!
Error:row!
Error:row!
Error:row!
Error:column!
Error:square!
Error:square!
Error:column!
Error:square!
Error:square!
OK!
Error:row!
Error:row!
Error:column!
OK!
Error:row!
Error:row!
Error:row!
Error:row!
Error:row!
Error:row!
Error:row!
Error:column!
Error:column!
Error:square!
Error:column!
OK!
Error:row!
Error:row!
Error:row!
Error:row!
Error:column!
Error:column!
Error:square!
Error:column!
Error:column!
Error:square!
Error:column!
OK!
Error:row!
Error:column!
Error:column!
OK!
Error:row!
Error:row!
Error:row!
Error:row!
Error:row!
Error:row!
Error:column!
Error:column!
Error:column!
Error:column!
Error:column!
OK!
Error:row!
Error:row!
Error:row!
Error:column!
Error:column!
Error:column!
Error:column!
Error:column!
Error:column!
Error:column!
Error:column!
OK!
OK!
9
1
2
3
4
5
6
7
8
9
+-+-+-+-+-+-+-+-+-+
|0|0|0|0|0|0|0|0|0|
+-+-+-+-+-+-+-+-+-+
|0|0|0|1|0|0|0|0|0|
+-+-+-+-+-+-+-+-+-+
|0|0|0|0|0|0|1|0|0|
+-+-+-+-+-+-+-+-+-+
|0|1|0|0|0|0|0|0|0|
+-+-+-+-+-+-+-+-+-+
|0|0|0|0|1|0|0|0|0|
+-+-+-+-+-+-+-+-+-+
|0|0|0|0|0|0|0|1|0|
+-+-+-+-+-+-+-+-+-+
|0|0|1|0|0|0|0|0|0|
+-+-+-+-+-+-+-+-+-+
|0|0|0|0|0|1|0|0|0|
+-+-+-+-+-+-+-+-+-+
|0|0|0|0|0|0|0|0|1|
+-+-+-+-+-+-+-+-+-+
该样例的数据规模与第 6 / 7 个测试点相同。
这道题目,直接模拟就可以了,但要注意细节以及一些很妙的操作:
首先是字符组的存入:注意将其他的字符进行排除:
1 for(int i=1;i<=19;i++){ 2 cin>>s; 3 if(i&1)continue;//奇数 4 for(int j=1;j<=9;j++) 5 c[0][i/2][j]=s[j*2-1]; 6 }
然后就是分类讨论:
char c[105][10][10];//前面用于备份每一次操作后的数独(第一次看到这种操作,太强了)
cin>>T; for(int i=1;i<=T;i++){ cin>>s; if(s[0]==\'I\')x=in,y=in,k=in,insert(i,x,y,k);//in:快读{i记录每一次操作} else if(s[0]==\'D\')x=in,y=in,del(i,x,y); else if(s[0]==\'Q\')x=in,y=in,query(i,x,y); else if(s[0]==\'M\')x=in,y=in,merge(i,x,y); else print(i); }
1:插入:
1 void insert(int n,int x,int y,int k){ 2 for(int i=1;i<=9;i++) 3 for(int j=1;j<=9;j++) 4 c[n][i][j]=c[n-1][i][j];//备份 5 if(c[n][x][y]!=\'0\'){ 6 cout<<"Error!"<<endl; 7 return; 8 } 9 for(int i=1;i<=9;i++) 10 if(c[n][x][i]==k+\'0\'){ 11 cout<<"Error:row!"<<endl; 12 return;//冲突1 13 } 14 for(int i=1;i<=9;i++) 15 if(c[n][i][y]==k+\'0\'){ 16 cout<<"Error:column!"<<endl; 17 return;//冲突2 18 } 19 int gg=(x-1)/3*3+(y-1)/3+1; 20 for(int i=0;i<=2;i++) 21 for(int j=0;j<=2;j++) 22 if(c[n][i+xs[gg]][j+ys[gg]]==k+\'0\'){ 23 cout<<"Error:square!"<<endl; 24 return;//冲突3 25 } 26 cout<<"OK!"<<endl; 27 c[n][x][y]=k+\'0\'; 28 }
2:删除:
1 void del(int n,int x,int y){ 2 for(int i=1;i<=9;i++) 3 for(int j=1;j<=9;j++) 4 c[n][i][j]=c[n-1][i][j];//注意备份 5 if(c[n][x][y]==\'0\') 6 cout<<"Error!"<<endl; 7 else{ 8 cout<<"OK!"<<endl; 9 c[n][x][y]=\'0\'; 10 } 11 }
3:查询:
1 int can[10],ans; 2 void query(int n,int x,int y){ 3 for(int i=1;i<=9;i++) 4 for(int j=1;j<=9;j++) 5 c[n][i][j]=c[n-1][i][j]; 6 if(c[n][x][y]!=\'0\'){cout<<"Error!"<<endl;} 7 memset(can,0,sizeof(can));ans=0; 8 int gg=(x-1)/3*3+(y-1)/3+1; 9 for(int i=1;i<=9;i++) 10 can[c[n][x][i]-\'0\']=1; 11 for(int i=1;i<=9;i++) 12 can[c[n][i][y]-\'0\']=1; 13 for(int i=0;i<=2;i++) 14 for(int j=0;j<=2;j++) 15 can[c[n][i+xs[gg]][j+ys[gg]]-\'0\']=1;//记录不满足的数(因为冲突) 16 for(int i=1;i<=9;i++) 17 if(!can[i]) ans++; 18 cout<<ans<<endl; 19 for(int i=1;i<=9;i++) 20 if(!can[i]) cout<<i<<endl; 21 }
4:合并:
1 int ansx,ansy; 2 void merge(int n,int x,int y){ 3 for(int i=1;i<=9;i++) 4 for(int j=1;j<=9;j++){ 5 int flag=0; 6 if(c[x][i][j]!=\'0\'){ 7 flag=1; 8 for(int k=1;k<=9;k++) 9 if(c[n][i][k]==c[x][i][j]){ 10 flag=0;break; 11 } 12 for(int k=1;k<=9;k++) 13 if(c[n][k][j]==c[x][i][j]){ 14 flag=0;break; 15 } 16 int wh=(i-1)/3*3+(j-1)/3+1; 17 for(int l=0;l<=2;l++) 18 for(int r=0;r<=2;r++) 19 if(c[n][l+xs[wh]][r+ys[wh]]==c[x][i][j]){ 20 flag=0;break; 21 } 22 } 23 if(flag){ 24 c[n][i][j]=c[x][i][j]; 25 ansx++; 26 continue; 27 } 28 if(c[y][i][j]!=\'0\'){ 29 flag=1; 30 for(int k=1;k<=9;k++) 31 if(c[n][i][k]==c[y][i][j]){ 32 flag=0;break; 33 } 34 for(int k=1;k<=9;k++) 35 if(c[n][k][j]==c[y][i][j]){ 36 flag=0;break; 37 } 38 int wh=(i-1)/3*3+(j-1)/3+1; 39 for(int l=0;l<=2;l++) 40 for(int r=0;r<=2;r++) 41 if(c[n][l+xs[wh]][r+ys[wh]]==c[y][i][j]){ 42 flag=0;break; 43 } 44 } 45 if(flag){ 46 c[n][i][j]=c[y][i][j]; 47 ansy++; 48 continue; 49 } 50 c[n][i][j]=\'0\'; 51 } 52 cout<<ansx<<" "<<ansy<<endl; 53 ansx=0,ansy=0;//注意多次操作要恢复 54 }
总代码:
1 #include<bits/stdc++.h> 2 using namespace std; 3 #define int long long 4 #define in read() 5 inline int read(){ 6 int p=0,f=1; 7 char c=getchar(); 8 while(!isdigit(c)){ 9 if(c==\'-\')f=-1; 10 c=getchar(); 11 } 12 while(isdigit(c)){ 13 p=p*10+c-\'0\'; 14 c=getchar(); 15 } 16 return p*f; 17 } 18 char c[105][10][10]; 19 string s; 20 int xs[10]={0,1,1,1,4,4,4,7,7,7}; 21 int ys[10]={0,1,4,7,1,4,7,1,4,7}; 22 void insert(int n,int x,int y,int k){ 23 for(int i=1;i<=9;i++) 24 for(int j=1;j<=9;j++) 25 c[n][i][j]=c[n-1][i][j]; 26 if(c[n][x][y]!=\'0\'){ 27 cout<<"Error!"<<endl; 28 return; 29 } 30 for(int i=1;i<=9;i++) 31 if(c[n][x][i]==k+\'0\'){ 32 cout<<"Error:row!"<<endl; 33 return; 34 } 35 for(int i=1;i<=9;i++) 36 if(c[n][i][y]==k+\'0\'){ 37 cout<<"Error:column!"<<endl; 38 return; 39 } 40 int gg=(x-1)/3*3+(y-1)/3+1; 41 for(int i=0;i<=2;i++) 42 for(int j=0;j<=2;j++) 43 if(c[n][i+xs[gg]][j+ys[gg]]==k+\'0\'){ 44 cout<<"Error:square!"<<endl; 45 return; 46 } 47 cout<<"OK!"<<endl; 48 c[n][x][y]=k+\'0\'; 49 } 50 void del(int n,int x,int y){ 51 for(int i=1;i<=9;i++) 52 for(int j=1;j<=9;j++) 53 c[n][i][j]=c[n-1][i][j]; 54 if(c[n][x][y]==\'0\')cout<<"Error!"<<endl; 55 else{cout<<"OK!"<<endl;c[n][x][y]=\'0\';} 56 } 57 int can[10],ans; 58 void query(int n,int x,int y){ 59 for(int i=1;i<=9;i++) 60 for(int j=1;j<=9;j++) 61 c[n][i][j]=c[n-1][i][j]; 62 if(c[n][x][y]!=\'0\'){cout<<"Error!"<<endl;} 63 memset(can,0,sizeof(can));ans=0; 64 int gg=(x-1)/3*3+(y-1)/3+1; 65 for(int i=1;i<=9;i++) 66 can[c[n][x][i]-\'0\']=1; 67 for(int i=1;i<=9;i++) 68 can[c[n][i][y]-\'0\']=1; 69 for(int i=0;i<=2;i++) 70 for(int j=0;j<=2;j++) 71 can[c[n][i+xs[gg]][j+ys[gg]]-\'0\']=1; 72 for(int i=1;i<=9;i++) 73 if(!can[i]) ans++; 74 cout<<ans<<endl; 75 for(int i=1;i<=9;i++) 76 if(!can[i]) cout<<i<<endl; 77 } 78 int ansx,ansy; 79 void merge(int n,int x,int y){ 80 for(int i=1;i<=9;i++) 81 for(int j=1;j<=9;j++){ 82 int flag=0; 83 if(c[x][i][j]!=\'0\'){ 84 flag=1; 85 for(int k=1;k<=9;k++) 86 if(c[n][i][k]==c[x][i][j]){ 87 flag=0;break; 88 } 89 for(int k=
观察输出发现,这是在交换行的过程中出现的错误。对交换行代码进行检查。
代码错误最终确认在SudokuMaker.cpp 中的void generateFullSwappedRowSudoku(int level);函数,源代码为:
generateFullSwappedRowSudoku(level + 1);//不进行交换
swapRow(4, 5);
//showSudoku();
generateFullSwappedRowSudoku(level + 1);
swapRow(4, 6);
//showSudoku();
generateFullSwappedRowSudoku(level + 1);
swapRow(5, 6);
//showSudoku();
generateFullSwappedRowSudoku(level + 1);
swapRow(4, 5);
//showSudoku();
generateFullSwappedRowSudoku(level + 1);
swapRow(4, 6);
//showSudoku();
generateFullSwappedRowSudoku(level + 1);
添加了对其中的代码注释之后解决该问题。原因是在后续的输出中存在不交换即输出的函数,中间层的交换后立即输出与后续的不交换即输出产生了冲突,修改之后代码正确。
后在1e3和1e4内进行循环测试没有发现重复。相关代码可以参见集成测试项目中的RepeationTest.
可以合理认为测试是成功的。
二、 求解算法测试
首先生成一定数量的数独。数独问题生成器在集成测试项目(IntegrationTest项目)中的SudokuProblemMaker中。根据数独生成算法生成的数独文件读入挖空并输出得到不同1e3到1e6数量的数独问题。生成的问题上传至百度网盘。
对该数独进行求解,在测试过程中取消对数独检查代码(正式生成程序时为加快速度进行注释)的注释如下:
对其进行求解输出测试发现无误。
三、 数独输出模块检查
手动对输出进行检查即可。
用户有个需求不清楚,就是再最后一个数独之后是否有空行。自行理解输出如下:
四、 命令解析测试
详细测试已在单元测试中做过。GoogleTest的代码在gtest项目中。需要在debug模式下运行,release没有做配置。
五、 集成测试
通过一系列测试,测试通过。
以上是关于2021.11.2测试-T1数独的主要内容,如果未能解决你的问题,请参考以下文章