数独生成和求解
项目地址
解题思路
1.生成
对一个合法的数独进行整行或整列的交换,所得数独仍然合法。在固定左上角数字的情况下,一个固定的数独可以变换出2!*3!*3!*2!*3!*3!=5184个不同的数独,由此只需得到200个不能通过整行整列交换使彼此相同的固定数独即可。可对第一个固定数独的每个九宫格进行全排列得到。
2.求解
求解算法参考了李显龙的数独求解算法
把1到9逐一放到数独中去,然后验证是否是合法数独。如果是合法的将数字放入数独中去,对新的数独做递归,直到填满整个数独。
实现过程
类:输入处理
函数:数独生成(create,exchange,save),数独求解(solution,solve,place,nextseq)
流程图
单元测试设计(结果可见于性能分析)
生成1000000个数独;
求解最难数独;
性能分析和改进
生成1000000个数独进行测试(附clock函数计时)
求解最难数独(vs的性能分析不知道什么原因在求解时运行不了)
于是采用了clock函数计时
时间基本在0.02s以内
改进思路: 生成一个输出一个改为存储下来一起输出;最初暴力求解,后参考李显龙的求解算法进行修改。
消耗最大的函数:create(生成数独)
关键代码
void create(int n)
{
int a[9] = { 1,2,9,4,5,6,7,8,3 };
while (1)
{
shudu[0][0] = shudu[1][6] = shudu[2][3] = shudu[3][2] = shudu[4][8] = shudu[5][5] = shudu[6][1] = shudu[7][7] = shudu[8][4] = 3;
shudu[0][1] = shudu[1][7] = shudu[2][4] = shudu[3][0] = shudu[4][6] = shudu[5][3] = shudu[6][2] = shudu[7][8] = shudu[8][5] = a[1];
shudu[0][2] = shudu[1][8] = shudu[2][5] = shudu[3][1] = shudu[4][7] = shudu[5][4] = shudu[6][0] = shudu[7][6] = shudu[8][3] = a[0];
shudu[0][3] = shudu[1][0] = shudu[2][6] = shudu[3][5] = shudu[4][2] = shudu[5][8] = shudu[6][4] = shudu[7][1] = shudu[8][7] = a[5];
shudu[0][4] = shudu[1][1] = shudu[2][7] = shudu[3][3] = shudu[4][0] = shudu[5][6] = shudu[6][5] = shudu[7][2] = shudu[8][8] = a[4];
shudu[0][5] = shudu[1][2] = shudu[2][8] = shudu[3][4] = shudu[4][1] = shudu[5][7] = shudu[6][3] = shudu[7][0] = shudu[8][6] = a[3];
shudu[0][6] = shudu[1][3] = shudu[2][0] = shudu[3][8] = shudu[4][5] = shudu[5][2] = shudu[6][7] = shudu[7][4] = shudu[8][1] = a[2];
shudu[0][7] = shudu[1][4] = shudu[2][1] = shudu[3][6] = shudu[4][3] = shudu[5][0] = shudu[6][8] = shudu[7][5] = shudu[8][2] = a[7];
shudu[0][8] = shudu[1][5] = shudu[2][2] = shudu[3][7] = shudu[4][4] = shudu[5][1] = shudu[6][6] = shudu[7][3] = shudu[8][0] = a[6];
memcpy(record, shudu, sizeof(shudu));
for (int i1 = 0; i1 < 2; i1++)
for (int i2 = 0; i2 < 6; i2++)
for (int i3 = 0; i3 < 6; i3++)
for (int j1 = 0; j1 < 2; j1++)
for (int j2 = 0; j2 < 6; j2++)
for (int j3 = 0; j3 < 6; j3++)
{
exchange(i1, i2, i3, j1, j2, j3);
if (countnum == n)
{
FILE* out;
fopen_s(&out, "sudoku.txt", "wt");
fputs(result, out);
fclose(out);
return;
}
}
next_permutation(a, a + 8);
}
}
void exchange(int x1, int x2, int x3, int y1, int y2, int y3)
{
memcpy(record, shudu, sizeof(shudu));
if (x1 == 1) colexchange(1, 2);
switch (x2)
{
case 1:
colexchange(4, 5);
break;
case 2:
colexchange(3, 4);
break;
case 3:
colexchange(3, 4);
colexchange(4, 5);
break;
case 4:
colexchange(3, 5);
colexchange(4, 5);
break;
case 5:
colexchange(3, 5);
break;
}
switch (x3)
{
case 1:
colexchange(7, 8);
break;
case 2:
colexchange(6, 7);
break;
case 3:
colexchange(6, 7);
colexchange(7, 8);
break;
case 4:
colexchange(6, 8);
colexchange(7, 8);
break;
case 5:
colexchange(6, 8);
break;
}
if (y1 == 1) rowexchange(1, 2);
switch (y2)
{
case 1:
rowexchange(4, 5);
break;
case 2:
rowexchange(3, 4);
break;
case 3:
rowexchange(3, 4);
rowexchange(4, 5);
break;
case 4:
rowexchange(3, 5);
rowexchange(4, 5);
break;
case 5:
rowexchange(3, 5);
break;
}
switch (y3)
{
case 1:
rowexchange(7, 8);
break;
case 2:
rowexchange(6, 7);
break;
case 3:
rowexchange(6, 7);
rowexchange(7, 8);
break;
case 4:
rowexchange(6, 8);
rowexchange(7, 8);
break;
case 5:
rowexchange(6, 8);
break;
}
save();
}
int NextSeq(int S)
{
int S2, Square, Possibles, BitCount;
int T, MinBitCount = 100;
for (T = S; T < 81; T++)
{
Square = Sequence[T];
Possibles = Block[InBlock[Square]] & Row[InRow[Square]] & Col[InCol[Square]];
BitCount = 0;
while (Possibles)
{
Possibles &= ~(Possibles & -Possibles);
BitCount++;
}
if (BitCount < MinBitCount)
{
MinBitCount = BitCount;
S2 = T;
}
}
return S2;
}
void Place(int S)
{
LevelCount[S]++;
Count++;
if (S >= 81)
{
PrintArray();
return;
}
int S2 = NextSeq(S);
SwapSeqEntries(S, S2);
int Square = Sequence[S];
int BlockIndex = InBlock[Square],
RowIndex = InRow[Square],
ColIndex = InCol[Square];
int Possibles = Block[BlockIndex] & Row[RowIndex] & Col[ColIndex];
while (Possibles)
{
int valbit = Possibles & (-Possibles); // Lowest 1 bit in Possibles
Possibles &= ~valbit;
Entry[Square] = valbit;
Block[BlockIndex] &= ~valbit;
Row[RowIndex] &= ~valbit;
Col[ColIndex] &= ~valbit;
Place(S + 1);
Entry[Square] = BLANK; // Could be moved out of the loop
Block[BlockIndex] |= valbit;
Row[RowIndex] |= valbit;
Col[ColIndex] |= valbit;
}
SwapSeqEntries(S, S2);
}
时间分配
stages | 预估耗时/分钟 | 实际耗时/分钟 |
计划 | 30 | 35 |
-估计耗时 | 30 | 35 |
开发 | 1500 | 2000 |
-需求分析 | 30 | 35 |
-生成设计文档 | 35 | 30 |
-设计复审 | 20 | 25 |
-代码规范 | 60 | 50 |
-具体设计 | 60 | 90 |
-具体编码 | 750 | 1000 |
-代码复查 | 90 | 120 |
-测试 | 400 | 600 |
报告 | 120 | 150 |
-测试报告 | 30 | 40 |
-计算工作量 | 30 | 45 |
-总结/改进计划 | 60 | 65 |
合计 | 1650 | 2185 |