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数独的主要内容,如果未能解决你的问题,请参考以下文章

软件工程——数独 集成测试

第二次作业——个人项目实战:数独

软件基础个人工程——数独4

软件工程——数独 总结报告

软件工程——数独 性能测试2

数独小算法,测试通过(Java)