数独

数独通法[可解决任何数独问题](仅供参考)

第一步:看横行(原则:这行已确定数大于等于四)

每一个空格写入可能的数字(根据横纵行已有的,但不看九宫)

第二步:看九宫

划去无机会的数字

第三步;重复1

第四步:重复2

此时,已基本每个空格都有数字了(一般数独已解),并且横纵行,九宫原则(明显原则)均已用尽.

隐含原则1:{若一个单元(横行\纵行\九宫)某组内未确定格数,与其内部元素数相同,则这几个元素必在这几格内}例:

某一横行内所填确定数字如下:

(1.2)(6)(2.3.4)(7)(5.3)(9)(2.4)(8)(1.4)

在第1.3.7.9格(4个)内含1.2.3.4四个元素

所以,这四个数只能在其中,所以第五格内3去掉

第五步:重复1.2,利用隐含原则1

第六步:检验全局,利用1_5

此时仅仅余下几个格了(难的数独已解),还有第二隐含原则:

(1.2)(6)(2.3.4)(7)(5.3,8)(9,1)(2.4)(8,9)(1.4)

这一行很复杂,隐含原则一也很难奏效

但可见,数5在这一行仅有一次机会,所以,第五格只能是它!

第七步:重复1.2,利用隐含原则2

第八步:检验全局,利用1_7

所有数独已解,若解不出来,三种原因

1你解错了 2有一个条件没看见 3这个数独有问题

完毕!

数独技巧

数独技巧

格,那么就只能出现在这个宫格了.对于唯一候选数出现行,九宫格的情况,处理方法完全相同。

数独技巧

这是制作好的一张候选数表,注意观察B5,B9,D1。

可以看出在第1列,数字9只在D1出现。在第5列,数字3只在B5出现。在B9所处的九宫格里,数字9只有在B9出现。所以"9"是第1列的隐形唯一候选数,"3"是第5列的隐形唯一候选数,"9"是A7九宫格的隐形唯一候选数。[1]

编辑本段三链数删减法

找出某一列、某一行或某一个九宫格中的某三个宫格候选数中,相异的数字不超过3个的情形,进而将这3个数字自其它宫格的候选数中删减掉的方法就叫做三链数删减法。隐性三链数删减法:在某行,存在三个数字出现在相同的宫格内,在本行的其它宫格均不包含这三个数字,我们称这个数对是隐形三链数.那么这三个宫格的候选数中的其它数字都可以排除.

当隐形三链数出现在列,九宫格,处理方法是完全相同的.矩形顶点删减法,矩形顶点删减法和直观法讲到的矩形摒除法分析方法是一样的。矩形顶点删减法在识别时比较不容易找到,所以最好先使用其它的方法。三链数删减法的原理如下面图示:

在H行,H2,H5,H7的候选数(12),(23),(13),构成三链数,那么123这三个数在H行将只能出现在H2,H5,H7,那么本行其它宫格就可以删除这3个候选数了。这是三链数发生在行的情况。

在G7所在九宫格,G7,H8,I9的候选数(12),(23),(13),构成三链数,那么123这三个数在这个九宫格将只能出现在G7,H8,I9,那么本九宫格其它宫格就可以删除这3个候选数了。这是三链数发生在九宫格的情况。

三链数是数对的扩展,我们在对上面的三链数进行扩展,得到右边的特殊的三链数,只要保证在3个宫格内,其包含的候选数也为3个,就都

符合我们的要求,比如(123,123,123),(12,123,123)或(12,23,123)都符合要求。

我们进一步再扩充,发现只要在N个宫格内,其包含的候选数也恰为N 个,那么处理和三链数是相同的道理,这样就形成了四链数,比如

(12,23,34,14),(123,123,14,1234)等。甚至可以扩充到五链数,七链数(虽然在实际解题中作用不大了)。平时我们用到最多的就是三链数,四链数了。

在A4所在九宫格,我们看到B4~B6,形成三链数,则本九宫格其它宫格就可以去除候选数"2","7","9",这样就得到C6=4。

同上面完全相同的一副图,在A行,A7~A9形成由179构成的三链数,排除本行其它宫格的候选数179后得到A3=3。

编辑本段三链列删减法

三链列删减法是矩形顶点删减法的扩展,如果不清楚矩形顶点删减法,可以参考矩形顶点删减法,以便于更容易理解本节内容。利用“找出某个数字在某三列仅出现在相同三行的情形,进而将该数字自这三行其他宫格候选数中删减掉”;或“找出某个数字在某三行仅出现在相同三列的情形,进而将该数字自这三列其他宫格候选数中删减掉”的方法就叫做三链列删减法。关键数删减法在进入到解题后期,利用前面讲到的唯一候选数法、隐性唯一候选数法、区块删减法、数对删减法、隐性数对删减法、三链数删减法、隐性三链数删减法、矩形顶点删减法、三链列删减法都无法有进展的时候,可以考虑使用关键数删减法。关键数删减法就是在后期找到一个数,这个数在行(或列,九宫格)仅出现两次的数字。我们假定这个数在其中一个宫格类,继续求解,如果发生错误,则确定我们的假设错误。如果继续求解仍然出现困难,不妨假设这个数在另外一个宫格,看能不能得到错误。这就是关键数删减法。

如果数字“1”可能出现在B行、E行、G行的黄色宫格,则符合“某个数字在某三列仅出现在相同三行的情形”,符合三链列删减法的要求。

则红色宫格均不包含候选数“1”。

这时上图的一个变形。其中一行的“1”只能放在这一行的两个位置。处理和上图一样,红色宫格均可以排除候选数“1”。

数字"6"在第2列,第6列,第8列。均出现在A,B,I行。其中在第6列仅出现B,I行,仍然符合三链列删减法的要求。

编辑本段直观法解题技巧

数独直观法解题技巧主要有

单元限定法、单元排除法、区块排除法、唯一余解法、矩形排除法、逐行逐列依次扫描法、综合扫描法、唯一候选数法、隐性唯一候选数法、区

块删减法、数对删减法、隐性数对删减法、三链数删减法、隐性三链数删

减法、矩形顶点删减法、三链列删减法、关键数删减法、关连数删减法。

1.联除法。

在并排的三个九宫格中的两排寻找相同数字,再利用九宫格得出另一

排中该数字位置,该方法适用于中高级数独.

2.巡格法

找出在每个九宫格中出现频率较高的数字,得出该数字在其余九宫格

内位置,该方法应用于方法一之后。

3.排除法

这个方法是解决问题的关键,易被常人所忽略。在各行列或九宫格中

观察,若有个位置其它数字都不能填,就填余下的数字

4.待定法

此方法不常用却很有效。暂时确定某个数字在某个区域,再利用其来进行排除

5.行列法

此方法用于收官阶段,利用先从行列突破来提高解题效率。

6.假设法

作为一名高手,我不提倡这种方法。即在某个位置随机的填上一个数字,再进行推演,并有可能最终产生矛盾而否定结论.

7.频率法

这种方法相比于上一种方法更能提高效率。在某一行列或九宫格列举

出所有情况,再选择某位置中出现频率高的数字

8.候选数法

使用候选数法解数独题目需先建立候选数列表,根据各种条件,逐步

安全的清除每个宫格候选数的不可能取值的候选数,从而达到解题的目的。

使用候选数法一般能解比较复杂的数独题目,但是候选数法的使用没

有直观法那么直接,需要先建立一个候选数列表的准备过程,所以实际使

用时可以先利用直观法进行解题,到无法用直观法解题时再使用候选数法

解题。

候选数法解题的过程就是逐渐排除不合适的候选数的过程,所以在进

行候选数删除的时候一定要小心,确定安全地删除不合适的候选数,否则,很多时候只有重新做题了。有了计算机软件的帮助,使得候选数表的维护

变得轻松起来。

#include

#include

#include

char sd[81];

bool isok = false;

//显示数独

void show()

{

if (isok) puts("求解完成");

else puts("初始化完成");

for (int i = 0; i < 81; i++)

{

putchar(sd[i] + '0');

if ((i + 1) % 9 == 0) putchar('\n');

}

putchar('\n');

}

//读取数独

bool Init()

{

FILE *fp = fopen("in.txt", "rb");

if (fp == NULL) return false;

fread(sd, 81, 1, fp);

fclose(fp);

for (int i = 0; i < 81; i++)

{

if (sd[i] >= '1' && sd[i] <= '9') sd[i] -= '0'; else sd[i] = 0;

}

show();

return true;

}

//递归解决数独

void force(int k)

{

if (isok) return;

if (!sd[k])

{

for (int m = 1; m <= 9; m++)

{

bool mm = true;

for (int n = 0; n < 9; n++)

{

if ((m == sd[k/27*27+(k%9/3)*3+n+n/3*6]) || (m == sd[9*n+k%9]) || (m == sd[k/9*9+n]))

{

mm = false;

break;

}

}

if (mm)

{

sd[k] = m;

if (k == 80)

{

isok = true;

show();

return;

}

force(k + 1);

}

}

sd[k] = 0;

}

else

{

if (k == 80)

{

isok = true;

show();

return;

}

force(k + 1);

}

}

int main()

{

system("CLS");

if (Init())

{

double start = clock();

force(0);

printf("耗时%.0fms", clock() - start); }

else puts("初始化错误");

getchar();

}

相关文档
最新文档