SudokuSolver 2.4 程序实现

本次版本实现了 用C++实现的数独解题程序 SudokuSolver 2.3 及实例分析 里发现的第三个不完全收缩 grp 算法 thirdGreenWorld。

CQuizDealer 类声明部分的修改

class CQuizDealer
{
public:
...
void run(ulong tilsteps = 0);
void mode(std::string& ex) {
size_t pos = ex.find_first_not_of(" \t");
if (pos != std::string::npos) {
ex.erase(0, pos);
m_mode = (u8)strtoul(ex.c_str(), 0, 10);
}
printf("Working mode:%d (1:grp-only; 2:ply-only; other:both grp and ply)\n", (int)m_mode);
}
...
private:
...
CQuizDealer() : m_state(STA_UNLOADED), ..., m_mode(0) {};
...
bool completeShrinkByGrp(u8* pGrp);
u8 incompleteShrinkByGrp(u8* pGrp);
u8 firstGreenWorld(u8* pGrp);
u8 incompleteShrinkBy1GW(u8 valSum, u8* pCelSumExs, u8* pGrp);
bool sameCandidates(u8 cel1, u8 cel2);
u8 anotherGreenWorld(u8* pGrp);
u8 incompleteShrinkByAGW(u8 times, u8* pTimesVals, u8* pValsCells, u8* pGrp);
u8 thirdGreenWorld(u8* pGrp);
u8 incompleteShrinkBy3GW(u8 sum, std::set<u8>& valSet, u8* pGrp);
bool unionValsByCombi(u8 sum, u8* pCombi, u8* pGrp, std::set<u8>& unionSet);
...
ulong m_steps;
u8 m_mode; // 1:grp-only; 2:ply-only; other:both
...
};

去掉了 setOnlyGrpMode 接口,新增了 mode 接口,相应地,原先的 onlygrp 命令换成了 mode [1|2|0] 命令。

增加了 thirdGreenWorld 等接口。

filterCandidates 接口的小修改

u8 CQuizDealer::filterCandidates()
{
incSteps();
u8 ret = RET_PENDING;
if (m_mode != 2) {
for (u8 row = 0; row < 9; ++row)
if (ret = filterRowGroup(row))
return ret;
for (u8 col = 0; col < 9; ++col)
if (ret = filterColGroup(col))
return ret;
for (u8 blk = 0; blk < 9; ++blk)
if (ret = filterBlkGroup(blk))
return ret;
}
if (m_mode != 1) {
for (u8 row = 0; row < 9; ++row) {
ret = filterRowCandidatesEx(row);
if (IsDone(ret))
return ret;
}
for (u8 col = 0; col < 9; ++col) {
ret = filterColCandidatesEx(col);
if (IsDone(ret))
return ret;
}
}
if (ret == RET_SHRUNKEN) {
printf("incomplete shrink met, filter again\n");
return filterCandidates();
}
return ret;
}

修改后,可以只使用 grp 算法求解,也可以只使用 ply 算法求解,缺省是两者都用。

从旧的 filterOneGroup 接口实现中提炼出 firstGreenWorld

 1 u8 CQuizDealer::firstGreenWorld(u8* pGrp)
2 {
3 u8 size = pGrp[0];
4 u8 celSumExs[100] = {0};
5 for (u8 idx = 1; idx <= size; ++idx) {
6 u8 valSum = m_seqCell[pGrp[idx]].candidates[0];
7 u8 base = valSum * 10;
8 celSumExs[base] += 1;
9 u8 pos = base + celSumExs[base];
10 celSumExs[pos] = pGrp[idx];
11 }
12 for (u8 idx = 2; idx <= 6; ++idx) {
13 u8 ret = incompleteShrinkBy1GW(idx, celSumExs, pGrp);
14 if (ret != RET_PENDING)
15 return ret;
16 }
17 return RET_PENDING;
18 }

旧 incompleteShrinkByGrp 改为 incompleteShrinkBy1GW

 1 u8 CQuizDealer::incompleteShrinkBy1GW(u8 valSum, u8* pCelSumExs, u8* pGrp)
2 {
3 u8 base = valSum * 10;
4 if (pCelSumExs[base] < valSum)
5 return RET_PENDING;
6 u8 itemSum = 0;
7 Item items[9];
8 for (u8 pos = 1; pos <= pCelSumExs[base]; ++pos) {
9 u8 idx = 0;
10 for (; idx < itemSum; ++idx)
11 if (sameCandidates(pCelSumExs[base + pos], items[idx].celIdxs[0])) {
12 items[idx].celIdxs[items[idx].sameSum] = pCelSumExs[base + pos];
13 items[idx].sameSum++;
14 break;
15 }
16 if (idx == itemSum) {
17 items[itemSum].sameSum = 1;
18 items[itemSum].celIdxs[0] = pCelSumExs[base + pos];
19 ++itemSum;
20 }
21 }
22 for (u8 idx = 0; idx < itemSum; ++idx) {
23 if (items[idx].sameSum > valSum)
24 return RET_WRONG;
25 }
26 bool shrunken = false;
27 for (u8 idx = 0; idx < itemSum; ++idx) {
28 if (items[idx].sameSum < valSum)
29 continue;
30 for (u8 pos = 1; pos <= pGrp[0]; ++pos) {
31 if (inSet(pGrp[pos], (u8*)&(items[idx])))
32 continue;
33 u8 isVals[10] = {0};
34 u8 cel1 = items[idx].celIdxs[0];
35 u8 cel2 = pGrp[pos];
36 intersection(m_seqCell[cel1].candidates, m_seqCell[cel2].candidates, isVals);
37 if (isVals[0] == 0)
38 continue;
39 shrunken = true;
40 for (u8 valIdx = 1; valIdx <= isVals[0]; ++valIdx) {
41 if (!removeVal(m_seqCell[cel2].candidates, isVals[valIdx]))
42 return RET_WRONG;
43 else
44 printf("1GW: %d shrunken out of [%d,%d]\n", (int)isVals[valIdx], (int)cel2 / 9 + 1, (int)cel2 % 9 + 1);
45 }
46 }
47 }
48 return (shrunken ? RET_SHRUNKEN : RET_PENDING);
49 }

新的 incompleteShrinkByGrp 接口实现

 1 u8 CQuizDealer::incompleteShrinkByGrp(u8* pGrp)
2 {
3 u8 ret = firstGreenWorld(pGrp);
4 if (ret != RET_PENDING)
5 return ret;
6 ret = anotherGreenWorld(pGrp);
7 if (ret != RET_PENDING)
8 return ret;
9 return thirdGreenWorld(pGrp);
10 }

新的 filterOneGroup 接口实现

u8 CQuizDealer::filterOneGroup(u8* pGrp)
{
return (completeShrinkByGrp(pGrp) ? RET_OK : incompleteShrinkByGrp(pGrp));
}

incompleteShrinkByAGW 接口实现的 bug 修改

u8 CQuizDealer::incompleteShrinkByAGW(u8 times, u8* pTimesVals, u8* pValsCells, u8* pGrp)
{
...
while (true) {
u8 celSet[10] = {0};
u8 valSet[10] = {0};
if (matchValsCells(times, combi, pTimesVals, pValsCells, celSet, valSet)) {
valSet[0] = times;
bool shrunken = false;
for (u8 idx = 1; idx <= times; ++idx) {
...
if (candiSum < times) {
printf("2GW: [%d,%d] candidates %d lower than times %d!\n", (int)(cel / 9 + 1), (int)(cel % 9 + 1), (int)candiSum, (int)times);
return RET_WRONG;
}
shrunken = true;
for (u8 pos = 1; pos <= m_seqCell[cel].candidates[0];) {
u8 val = m_seqCell[cel].candidates[pos];
if (inSet(val, valSet))
++pos;
else {
removeVal(m_seqCell[cel].candidates, val);
printf("2GW: %d shrunken out of [%d,%d]\n", (int)val, (int)(cel / 9 + 1), (int)(cel % 9 + 1));
}
}
}
...
}
if (!move2NextCombi(times, combi))
break;
}
return RET_PENDING;
}

新增 thirdGreenWorld 接口实现

 1 u8 CQuizDealer::thirdGreenWorld(u8* pGrp)
2 {
3 u8 grpSize = pGrp[0];
4 std::set<u8> valSet;
5 u8 lowSum = 9, highSum = 0;
6 for (u8 idx = 1; idx <= grpSize; ++idx) {
7 u8 valSum = m_seqCell[pGrp[idx]].candidates[0];
8 if (valSum < lowSum)
9 lowSum = valSum;
10 if (valSum > highSum)
11 highSum = valSum;
12 for (u8 vidx = 1; vidx <= valSum; ++vidx) {
13 u8 val = m_seqCell[pGrp[idx]].candidates[vidx];
14 valSet.insert(val);
15 }
16 }
17 if (valSet.size() != grpSize) {
18 printf("3GW: shrink went wrong\n");
19 return RET_WRONG;
20 }
21 if (highSum == valSet.size())
22 --highSum;
23 for (u8 sum = lowSum; sum <= highSum; ++sum) {
24 u8 ret = incompleteShrinkBy3GW(sum, valSet, pGrp);
25 if (ret != RET_PENDING)
26 return ret;
27 }
28 return RET_PENDING;
29 }

新增 incompleteShrinkBy3GW 接口实现

 1 u8 CQuizDealer::incompleteShrinkBy3GW(u8 sum, std::set<u8>& valSet, u8* pGrp)
2 {
3 u8 combi[10] = {0};
4 combi[0] = pGrp[0];
5 for (u8 idx = 0; idx < sum; ++idx)
6 combi[idx + 1] = idx;
7 while (true) {
8 std::set<u8> unionSet;
9 if (unionValsByCombi(sum, combi, pGrp, unionSet)) {
10 u8 compSet[10] = {0};
11 for (std::set<u8>::iterator it = valSet.begin(); it != valSet.end(); ++it)
12 if (unionSet.find(*it) == unionSet.end()) {
13 compSet[0] += 1;
14 compSet[compSet[0]] = *it;
15 }
16 combi[0] = sum; // for soon calling inSet properly
17 u8 cells[10] = {0};
18 for (u8 pos = 0; pos < pGrp[0]; ++pos) {
19 if (!inSet(pos, combi)) {
20 cells[0] += 1;
21 cells[cells[0]] = pos;
22 }
23 }
24 combi[0] = pGrp[0]; //back again
25 bool shrunken = false;
26 for (u8 idx = 1; idx <= cells[0]; ++idx) {
27 u8 pos = pGrp[cells[idx] + 1];
28 for (u8 inn = 1; inn <= m_seqCell[pos].candidates[0];) {
29 u8 val = m_seqCell[pos].candidates[inn];
30 if (inSet(val, compSet))
31 ++inn;
32 else {
33 shrunken = true;
34 removeVal(m_seqCell[pos].candidates, val);
35 printf("3GW: %d shrunken out of [%d,%d]\n", (int)val, (int)pos / 9 + 1, (int)pos % 9 + 1);
36 }
37 }
38 }
39 if (shrunken)
40 return RET_SHRUNKEN;
41 }
42 if (!move2NextCombi(sum, combi))
43 break;
44 }
45 return RET_PENDING;
46 }

新增 unionValsByCombi 接口实现

 1 bool CQuizDealer::unionValsByCombi(u8 sum, u8* pCombi, u8* pGrp, std::set<u8>& unionSet)
2 {
3 for (u8 idx = 1; idx <= sum; ++idx) {
4 u8 pos = pGrp[pCombi[idx] + 1];
5 u8 valSum = m_seqCell[pos].candidates[0];
6 if (valSum > sum)
7 return false;
8 for (u8 vidx = 1; vidx <= valSum; ++vidx) {
9 u8 val = m_seqCell[pos].candidates[vidx];
10 unionSet.insert(val);
11 }
12 if (unionSet.size() > sum)
13 return false;
14 }
15 return (unionSet.size() == sum);
16 }

其他小修改

// 1.0 2021/9/20
// 2.0 2021/10/2
// 2.1 2021/10/4
// 2.2 2021/10/10
// 2.3 2021/10/17
#define STR_VER "Sudoku Solver 2.4 2021/10/19 by readalps\n\n" void showOrderList()
{
printf(STR_VER);
printf("Order List:\n");
printf("load-quiz <file>: load quiz from file\n");
printf("show: show quiz info\n");
printf("mode [1|2|0]: query or change working mode\n");
printf("step: step forward\n");
printf("run: run till the end or a new solution met\n");
printf("runtil <steps>: run till certain steps run\n");
printf("bye: quit\n");
} void dealOrder(std::string& strOrder)
{
std::string strEx;
if ("bye" == strOrder)
setQuit();
else if (matchPrefixEx(strOrder, "load-quiz ", strEx))
CQuizDealer::instance()->loadQuiz(strEx);
else if ("show" == strOrder)
CQuizDealer::instance()->showQuiz();
else if (matchPrefixEx(strOrder, "mode", strEx))
CQuizDealer::instance()->mode(strEx);
else if ("step" == strOrder)
CQuizDealer::instance()->step();
else if ("run" == strOrder)
CQuizDealer::instance()->run();
else if (matchPrefixEx(strOrder, "runtil ", strEx)) {
ulong tilsteps = strtoul(strEx.c_str(), 0, 10);
CQuizDealer::instance()->run(tilsteps);
}
else
showOrderList();
}

实例分析

“最难”数独题

继续以 SudokuSolver 1.0:用C++实现的数独解题程序 【二】 里试验过的“最难”数独题为例做分析。

D:\read\num\Release>sudoku.exe

Order please:

Sudoku Solver 2.4 2021/10/19 by readalps

Order List:
load-quiz <file>: load quiz from file
show: show quiz info
mode [1|2|0]: query or change working mode
step: step forward
run: run till the end or a new solution met
runtil <steps>: run till certain steps run
bye: quit Order please:
load-quiz s.txt
Quiz loaded. Order please:
run
...
1014) col 8 complete shrunken by group
1017) Guess [1,6] level 8 at 1 out of 2
1018) row 3 complete shrunken by group
1020) row 3 complete shrunken by group
1GW: 8 shrunken out of [2,7]
1022) row 2 incomplete shrunken by group
1023) Guess [1,8] level 9 at 1 out of 2
1026) row 9 complete shrunken by group
1028) col 6 complete shrunken by group
1031) Guess [2,5] level 10 at 1 out of 2
1034) shrinking 4 from [6,3] went wrong
1035) Forward guess [2,5] level 10 at 2 out of 2
812 753 649
943 682 175
675 491 283 154 237 896
369 845 721
287 169 534 521 974 368
438 526 917
796 318 452 Done [steps:1040, solution sum:1].
Run time: 430 milliseconds; steps: 1040, solution sum: 1. Order please:

第二次 run 命令的输出信息为:

run
...
1GW: 2 shrunken out of [5,1]
1GW: 9 shrunken out of [5,1]
1GW: 2 shrunken out of [5,2]
1GW: 2 shrunken out of [5,4]
1GW: 9 shrunken out of [5,4]
1GW: 2 shrunken out of [5,8]
1GW: 9 shrunken out of [5,8]
1698) row 5 incomplete shrunken by group
1699) Guess [1,3] level 6 at 1 out of 2
1703) row 1 complete shrunken by group
1705) row 2 complete shrunken by group
1707) row 4 complete shrunken by group
1707) shrinking 9 from blk[5,1] went wrong
1708) Forward guess [1,3] level 6 at 2 out of 2
1709) shrinking 2 from [4,9] went wrong
1710) No more solution (solution sum is 1).
809 000 306
503 600 800
076 090 250 054 007 120
002 045 789
000 100 635 001 000 568
008 500 910
090 000 400 Invalid quiz [steps:1710] - no more solution (solution sum is 1)
Run time: 265 milliseconds; steps: 1710, solution sum: 1. Order please:

从输出的完整信息看,不再有“ply”信息,说明求解过程中只用到了 grp 算法,而没有用到 ply 算法。

第一次 run 命令走了 1040 步,求得一个解,用时约 430 毫秒;第二次 run 命令用了约 265 毫秒得出结论此 quiz 只有一个解,两次 run 命令共走了 1710 步。

退出程序并重新进入交互,这次显式仅用 grp 算法模式求解:

Order please:
bye D:\read\num\Release>sudoku.exe Order please:
mode
Working mode:0 (1:grp-only; 2:ply-only; other:both grp and ply) Order please:
mode 1
Working mode:1 (1:grp-only; 2:ply-only; other:both grp and ply) Order please:
load-quiz s.txt
Quiz loaded. Order please:
run
...
1GW: 8 shrunken out of [2,7]
1022) row 2 incomplete shrunken by group
1023) Guess [1,8] level 9 at 1 out of 2
1026) row 9 complete shrunken by group
1028) col 6 complete shrunken by group
1031) Guess [2,5] level 10 at 1 out of 2
1034) shrinking 4 from [6,3] went wrong
1035) Forward guess [2,5] level 10 at 2 out of 2
812 753 649
943 682 175
675 491 283 154 237 896
369 845 721
287 169 534 521 974 368
438 526 917
796 318 452 Done [steps:1040, solution sum:1].
Run time: 421 milliseconds; steps: 1040, solution sum: 1. Order please:
run
...
1GW: 9 shrunken out of [5,8]
1698) row 5 incomplete shrunken by group
1699) Guess [1,3] level 6 at 1 out of 2
1703) row 1 complete shrunken by group
1705) row 2 complete shrunken by group
1707) row 4 complete shrunken by group
1707) shrinking 9 from blk[5,1] went wrong
1708) Forward guess [1,3] level 6 at 2 out of 2
1709) shrinking 2 from [4,9] went wrong
1710) No more solution (solution sum is 1).
809 000 306
503 600 800
076 090 250 054 007 120
002 045 789
000 100 635 001 000 568
008 500 910
090 000 400 Invalid quiz [steps:1710] - no more solution (solution sum is 1)
Run time: 265 milliseconds; steps: 1710, solution sum: 1. Order please:
bye D:\read\num\Release>

从输出信息看,除了第一次 run 命令用时比之前略微减少(从 430 减为 421)之外,其他信息完全一致。

再看一下显式仅用 ply 算法模式求解的输出信息:

D:\read\num\Release>sudoku.exe

Order please:
load-quiz s.txt
Quiz loaded. Order please:
show
800 000 000
003 600 000
070 090 200 050 007 000
000 045 700
000 100 030 001 000 068
008 500 010
090 000 400 Order please:
mode 2
Working mode:2 (1:grp-only; 2:ply-only; other:both grp and ply) Order please:
run
...
1054) col 6 shrunken ply-1 by vblk 2
[2,8]: 5 7 shrunken to 7 worked by col-ply1.
1056) col 8 shrunken ply-1 by vblk 1
1059) Guess [2,5] level 10 at 1 out of 2
1063) shrinking 8 from [4,7] went wrong
1064) Forward guess [2,5] level 10 at 2 out of 2
812 753 649
943 682 175
675 491 283 154 237 896
369 845 721
287 169 534 521 974 368
438 526 917
796 318 452 Done [steps:1069, solution sum:1].
Run time: 468 milliseconds; steps: 1069, solution sum: 1. Order please:
run
...
1335) col 8 shrunken ply-2 by vblk 2
[4,9]: 1 2 4 6 9 shrunken to 1 4 6 9 worked by col-ply2.
[5,9]: 1 2 6 9 shrunken to 1 6 9 worked by col-ply2.
incomplete shrink met, filter again
1339) Guess [1,3] level 8 at 1 out of 2
...
2100) row 8 shrunken ply-1 by blk 2
[8,2]: 2 3 4 shrunken to 4 worked by row-ply2.
2102) row 8 shrunken ply-2 by blk 3
[6,1]: 2 7 9 shrunken to 7 worked by row-ply2.
[6,3]: 2 4 7 9 shrunken to 4 7 worked by row-ply2.
2104) row 6 shrunken ply-2 by blk 2
2104) shrinking 2 from [8,1] went wrong
2105) No more solution (solution sum is 1).
800 000 306
003 600 800
476 893 251 350 067 100
160 345 700
704 100 635 201 000 568
048 506 910
695 000 400 Invalid quiz [steps:2105] - no more solution (solution sum is 1)
Run time: 493 milliseconds; steps: 2105, solution sum: 1. Order please:

可以看出,仅用 ply 算法求解,比起仅用 grp 算法求解,用时和步数都略有增加。第二次 run 命令的输出里有几次如下的信息输出:

incomplete shrink met, filter again

这正好对应 用C++实现的数独解题程序 SudokuSolver 2.1 及实例分析 里所言的:这样的两次关联收缩,倘若第一次不完全收缩发生在第五轮的 col-ply 筛查阶段,就会导致第二次的完全收缩接续不上,进而多加一次猜测行为。这是一个可改进之处。2.2 版本改进之后一直没有碰到这种情形,直到这里仅用 ply 算法求解时才碰到。

另一道数独题

这一道据说也挺有难度:

005 300 000
800 000 020
070 010 500
400 005 300
010 070 006
003 200 080
060 500 009
004 000 030
000 009 700

把这 9 行数字放到一个文本文件(比如 D:\read\num\Release\s.txt)的头部位置。这次不对输出做删节处理,呈现完整的两次 run 命令输出:

D:\read\num\Release>sudoku.exe

Order please:
load-quiz s.txt
Quiz loaded. Order please:
run
2) row 2 complete shrunken by group
4) row 5 complete shrunken by group
2GW: 2 shrunken out of [4,3]
2GW: 8 shrunken out of [4,3]
2GW: 9 shrunken out of [4,3]
2GW: 5 shrunken out of [6,1]
2GW: 9 shrunken out of [6,1]
CelSet: [4,3] [6,1] ValSet: 6 7
6) blk 4 incomplete shrunken by group
7) Guess [6,2] level 1 at 1 out of 2
8) row 5 complete shrunken by group
11) Guess [4,3] level 2 at 1 out of 2
13) col 3 complete shrunken by group
16) Guess [2,3] level 3 at 1 out of 2
18) Guess [3,3] level 4 at 1 out of 2
24) col 8 complete shrunken by group
28) row 3 complete shrunken by group
30) row 1 complete shrunken by group
32) row 1 complete shrunken by group
35) shrinking 1 from [9,1] went wrong
36) Forward guess [3,3] level 4 at 2 out of 2
2GW: 1 shrunken out of [1,8]
2GW: 4 shrunken out of [1,8]
2GW: 6 shrunken out of [1,8]
2GW: 1 shrunken out of [4,8]
CelSet: [1,8] [4,8] ValSet: 7 9
37) col 8 incomplete shrunken by group
38) Guess [1,1] level 5 at 1 out of 2
40) shrinking 9 from [2,4] went wrong
41) Forward guess [1,1] level 5 at 2 out of 2
43) Guess [1,2] level 6 at 1 out of 2
46) row 2 complete shrunken by group
48) row 3 complete shrunken by group
50) row 4 complete shrunken by group
52) row 4 complete shrunken by group
54) shrinking 8 from [9,4] went wrong
55) Forward guess [1,2] level 6 at 2 out of 2
57) row 3 complete shrunken by group
59) row 8 complete shrunken by group
1GW: 8 shrunken out of [9,4]
1GW: 2 shrunken out of [9,5]
1GW: 8 shrunken out of [9,5]
1GW: 2 shrunken out of [9,9]
1GW: 8 shrunken out of [9,9]
61) row 9 incomplete shrunken by group
62) Guess [1,8] level 7 at 1 out of 2
64) shrinking 9 from [1,5] went wrong
65) Forward guess [1,8] level 7 at 2 out of 2
67) row 2 complete shrunken by group
69) row 4 complete shrunken by group
71) row 6 complete shrunken by group
73) col 4 complete shrunken by group
1GW: 4 shrunken out of [2,9]
75) blk 3 incomplete shrunken by group
76) Guess [1,5] level 8 at 1 out of 2
78) row 1 complete shrunken by group
81) Guess [1,7] level 9 at 1 out of 2
84) Guess [2,6] level 10 at 1 out of 2
87) row 9 complete shrunken by group
89) col 4 complete shrunken by group
92) Guess [4,2] level 11 at 1 out of 2
92) shrinking 8 from [8,7] went wrong
93) Forward guess [4,2] level 11 at 2 out of 2
93) shrinking 5 from [8,1] went wrong
94) Upward guess [2,6] level 10 at 2 out of 2
95) shrinking 5 from [9,9] went wrong
96) Upward guess [1,7] level 9 at 2 out of 2
96) shrinking 4 from blk[6,9] went wrong
97) Upward guess [1,5] level 8 at 2 out of 2
97) shrinking 7 from [2,9] went wrong
98) Upward guess [2,3] level 3 at 2 out of 2
102) row 3 complete shrunken by group
105) Guess [1,9] level 4 at 1 out of 2
106) row 4 complete shrunken by group
108) col 8 complete shrunken by group
2GW: 6 shrunken out of [8,4]
2GW: 8 shrunken out of [8,4]
2GW: 2 shrunken out of [8,6]
2GW: 6 shrunken out of [8,6]
2GW: 8 shrunken out of [8,6]
CelSet: [8,4] [8,6] ValSet: 1 7
110) row 8 incomplete shrunken by group
111) Guess [1,8] level 5 at 1 out of 2
117) shrinking 2 from [4,2] went wrong
118) Forward guess [1,8] level 5 at 2 out of 2
120) shrinking 8 from [9,9] went wrong
121) Upward guess [1,9] level 4 at 2 out of 2
123) Guess [1,7] level 5 at 1 out of 2
124) col 8 complete shrunken by group
2GW: 4 shrunken out of [2,4]
2GW: 1 shrunken out of [8,4]
2GW: 8 shrunken out of [8,4]
CelSet: [2,4] [8,4] ValSet: 6 7
126) col 4 incomplete shrunken by group
127) Guess [1,5] level 6 at 1 out of 2
145 327 698
839 654 127
672 918 543 496 185 372
218 473 956
753 296 481 367 542 819
984 761 235
521 839 764 Done [steps:131, solution sum:1].
Run time: 46 milliseconds; steps: 131, solution sum: 1. Order please:
run
132) Forward guess [1,5] level 6 at 2 out of 2
1GW: 4 shrunken out of [2,6]
135) row 2 incomplete shrunken by group
136) Guess [2,4] level 7 at 1 out of 2
138) row 3 complete shrunken by group
139) shrinking 8 from blk[8,7] went wrong
140) Forward guess [2,4] level 7 at 2 out of 2
142) row 3 complete shrunken by group
143) shrinking 8 from blk[8,7] went wrong
144) Upward guess [1,7] level 5 at 2 out of 2
146) shrinking 8 from [9,4] went wrong
147) Upward guess [4,3] level 2 at 2 out of 2
149) row 6 complete shrunken by group
151) col 8 complete shrunken by group
154) Guess [4,8] level 3 at 1 out of 2
157) row 6 complete shrunken by group
1GW: 4 shrunken out of [1,7]
1GW: 4 shrunken out of [2,7]
159) col 7 incomplete shrunken by group
160) Guess [3,1] level 4 at 1 out of 2
163) shrinking 8 from [9,5] went wrong
164) Forward guess [3,1] level 4 at 2 out of 2
165) row 2 complete shrunken by group
167) row 7 complete shrunken by group
169) row 9 complete shrunken by group
172) Guess [2,2] level 5 at 1 out of 2
174) Guess [1,2] level 6 at 1 out of 2
176) row 3 complete shrunken by group
178) col 6 complete shrunken by group
180) row 5 complete shrunken by group
183) row 8 complete shrunken by group
184) shrinking 2 from [8,7] went wrong
185) Forward guess [1,2] level 6 at 2 out of 2
187) row 2 complete shrunken by group
189) shrinking 5 from [9,1] went wrong
190) Upward guess [2,2] level 5 at 2 out of 2
193) row 1 complete shrunken by group
194) shrinking 6 from [8,6] went wrong
195) Upward guess [4,8] level 3 at 2 out of 2
196) row 6 complete shrunken by group
199) Guess [3,8] level 4 at 1 out of 2
2GW: 1 shrunken out of [1,7]
2GW: 8 shrunken out of [1,7]
2GW: 1 shrunken out of [2,7]
CelSet: [1,7] [2,7] ValSet: 6 9
201) col 7 incomplete shrunken by group
202) Guess [1,9] level 5 at 1 out of 2
203) shrinking 1 from [4,4] went wrong
204) Forward guess [1,9] level 5 at 2 out of 2
206) shrinking 1 from [4,4] went wrong
207) Upward guess [3,8] level 4 at 2 out of 2
208) col 3 complete shrunken by group
210) col 7 complete shrunken by group
212) col 6 complete shrunken by group
214) blk 1 complete shrunken by group
1GW: 1 shrunken out of [7,7]
1GW: 4 shrunken out of [7,7]
1GW: 1 shrunken out of [8,9]
1GW: 1 shrunken out of [9,9]
1GW: 4 shrunken out of [9,9]
216) blk 9 incomplete shrunken by group
217) Guess [1,9] level 5 at 1 out of 2
218) col 2 complete shrunken by group
221) shrinking 9 from [5,3] went wrong
222) Forward guess [1,9] level 5 at 2 out of 2
223) col 7 complete shrunken by group
225) col 7 complete shrunken by group
230) shrinking 8 from [4,4] went wrong
231) Upward guess [6,2] level 1 at 2 out of 2
232) row 6 complete shrunken by group
234) row 5 complete shrunken by group
236) row 6 complete shrunken by group
239) row 8 complete shrunken by group
241) row 9 complete shrunken by group
243) col 3 complete shrunken by group
245) blk 9 complete shrunken by group
248) Guess [1,2] level 2 at 1 out of 2
251) shrinking 7 from [1,9] went wrong
252) Forward guess [1,2] level 2 at 2 out of 2
254) row 3 complete shrunken by group
257) Guess [2,3] level 3 at 1 out of 2
1GW: 2 shrunken out of [9,1]
1GW: 8 shrunken out of [9,4]
1GW: 2 shrunken out of [9,5]
1GW: 8 shrunken out of [9,5]
1GW: 2 shrunken out of [9,9]
1GW: 8 shrunken out of [9,9]
258) row 9 incomplete shrunken by group
259) Guess [1,1] level 4 at 1 out of 2
260) shrinking 6 from [2,4] went wrong
261) Forward guess [1,1] level 4 at 2 out of 2
3GW: 2 shrunken out of [7,5]
3GW: 8 shrunken out of [7,5]
263) col 5 incomplete shrunken by group
264) Guess [2,7] level 5 at 1 out of 2
266) shrinking 2 from [7,7] went wrong
267) Forward guess [2,7] level 5 at 2 out of 2
268) row 1 complete shrunken by group
271) row 1 complete shrunken by group
273) row 5 complete shrunken by group
3GW: shrink went wrong
275) row 7 shrink by group went WRONG
276) Upward guess [2,3] level 3 at 2 out of 2
280) row 5 complete shrunken by group
282) col 7 complete shrunken by group
283) shrinking 6 from [2,4] went wrong
284) No more solution (solution sum is 1).
145 300 900
839 050 127
672 018 543 426 005 371
518 473 296
793 261 485 067 500 819
954 000 632
081 609 750 Invalid quiz [steps:284] - no more solution (solution sum is 1)
Run time: 63 milliseconds; steps: 284, solution sum: 1. Order please:
bye D:\read\num\Release>

可以看到,这个 quiz 的求解过程,出现的最深猜测级别为 11 级:

92) Guess [4,2] level 11 at 1 out of 2

仅比前面那个 quiz 少一级。但从用时和步数看,这个 quiz 要容易不少。

用C++实现的数独解题程序 SudokuSolver 2.4 及实例分析的更多相关文章

  1. 用C++实现的数独解题程序 SudokuSolver 2.3 及实例分析

    SudokuSolver 2.3 程序实现 用C++实现的数独解题程序 SudokuSolver 2.2 及实例分析 里新发现了一处可以改进 grp 算法的地方,本次版本实现了对应的改进 grp 算法 ...

  2. 用C++实现的数独解题程序 SudokuSolver 2.2 及实例分析

    SudokuSolver 2.2 程序实现 根据 用C++实现的数独解题程序 SudokuSolver 2.1 及实例分析 里分析,对 2.1 版做了一些改进和尝试. CQuizDealer 类声明部 ...

  3. 用C++实现的数独解题程序 SudokuSolver 2.1 及实例分析

    SudokuSolver 2.1 程序实现 在 2.0 版的基础上,2.1 版在输出信息上做了一些改进,并增加了 runtil <steps> 命令,方便做实例分析. CQuizDeale ...

  4. 用C++实现的数独解题程序 SudokuSolver 2.7 及实例分析

    引言:一个 bug 的发现 在 MobaXterm 上看到有内置的 Sudoku 游戏,于是拿 SudokuSolver 求解,随机出题,一上来是个 medium 级别的题: 073 000 060 ...

  5. 用C++实现的数独解题程序 SudokuSolver 2.6 的新功能及相关分析

    SudokuSolver 2.6 的新功能及相关分析 SudokuSolver 2.6 的命令清单如下: H:\Read\num\Release>sudoku.exe Order please: ...

  6. SudokuSolver 1.0:用C++实现的数独解题程序 【二】

    本篇是 SudokuSolver 1.0:用C++实现的数独解题程序 [一] 的续篇. CQuizDealer::loadQuiz 接口实现 1 CQuizDealer* CQuizDealer::s ...

  7. SudokuSolver 2.0:用C++实现的数独解题程序 【一】

    SudokuSolver 2.0 实现效果 H:\Read\num\Release>sudoku.exe Order please: Sudoku Solver 2.0 2021/10/2 by ...

  8. SudokuSolver 1.0:用C++实现的数独解题程序 【一】

    SudokuSolver 1.0 用法与实现效果 SudokuSolver 是一个提供命令交互的命令行程序,提供的命令清单有: H:\Read\num\Release>sudoku.exe Or ...

  9. 数独GUI程序项目实现

    数独GUI程序项目实现 导语:最近玩上了数独这个游戏,但是找到的几个PC端数独游戏都有点老了...我就想自己做一个数独小游戏,也是一个不错的选择. 前期我在网上简单地查看了一些数独游戏的界面,代码.好 ...

随机推荐

  1. hibernate关联关系(一对多)

    什么是关联(association)关联指的是类之间的引用关系.如果类A与类B关联,那么被引用的类B将被定义为类A的属性.例如: class B{ private String name; } pub ...

  2. Docker(42)- 镜像原理之联合文件系统

    前言 学习狂神老师的 Docker 系列课程,并总结 镜像是什么 镜像是一种轻量级.可执行的独立软件保,用来打包软件运行环境和基于运行环境开发的软件 他包含运行某个软件所需的所有内容,包括代码.运行时 ...

  3. Linux 动态库的编译和使用

    1. 动态链接库简介 动态库又叫动态链接库,是程序运行的时候加载的库,当动态链接库正确安装后,所有的程序都可以使用动态库来运行程序.动态库是目标文件的集合,目标文件在动态库中的组织方式是按特殊的方式组 ...

  4. 基于flex布局的header

    一.如图 二.思路 1.定义header,设置宽为100%,高为60px,设置绝对定位,使其为漂浮层.在header里添加container,宽设置为版心宽度,并且设置flex布局. 2.在conta ...

  5. 轻量化模型系列--GhostNet:廉价操作生成更多特征

    ​  前言  由于内存和计算资源有限,在嵌入式设备上部署卷积神经网络 (CNN) 很困难.特征图中的冗余是那些成功的 CNN 的一个重要特征,但在神经架构设计中很少被研究. 论文提出了一种新颖的 Gh ...

  6. 一文搞懂Python Unittest测试方法执行顺序

    大家好~我是米洛! 欢迎关注我的公众号测试开发坑货,一起交流!点赞收藏关注,不迷路. Unittest unittest大家应该都不陌生.它作为一款博主在5-6年前最常用的单元测试框架,现在正被pyt ...

  7. 《挑战程序设计竞赛》——DFS

    DFS(深度优先搜索) 简介 深度优先搜索(DFS,Depth-First Search)是搜索的手段之一.它从某个状态开始,不断的转移状态直到无法转移.然后退回到前一步的状态,继续转移到其他状态,如 ...

  8. 为什么在匿名内部类中引用外部对象要加final修饰符

    当所在的方法的形参需要被内部类里面使用时,该形参必须为final. 为什么必须要为final呢? 首先我们知道在内部类编译成功后,它会产生一个class文件,该class文件与外部类并不是同一clas ...

  9. CDI Features inJavaEE 的上下文和依赖注入

    基本的CDI的功能: 类型安全:CDI使用Java类型来解析注入,而不是通过(字符串)名称注入对象.当类型不足时, 可以使用限定符 注释.这允许编译器轻松检测错误,并提供简单的重构. POJO:几乎每 ...

  10. 【PHP数据结构】图的概念和存储结构

    随着学习的深入,我们的知识也在不断的扩展丰富.树结构有没有让大家蒙圈呢?相信我,学完图以后你就会觉得二叉树简直是简单得没法说了.其实我们说所的树,也是图的一种特殊形式. 图的概念 还记得我们学习树的第 ...