数独是如何计算的

数独是如何计算的,第1张

数独用到计算的就是“45法则”:

每行的数字和=45

每列的数字和=45

每宫的数字和=45

有以下几个方法

联除法:在并排的三个九宫格中的两排寻找相同数字,再利用九宫格得出另一排中该数字位置,该方法适用于中高级数独

巡格法:找出在每个九宫格中出现频率较高的数字,得出该数字在其余九宫格内位置,该方法应用于方法一之后

排它法:这个方法是解决问题的关键,易被常人所忽略在各行列或九宫格中观察,若有个位置其它数字都不能填,就填余下的数字

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

假设法:即在某个位置随机的填上一个数字,再进行推演,并有可能最终产生矛盾而否定结论行列法:此方法用于收官阶段,利用先从行列突破来提高解题效

频率法:这种方法相比于上一种方法更能提高效率在某一行列或九宫格列举出所有情况,再选择某位置中出现频率高的数字。

为方便起见,建名称“数独盘”和“可选数”,分别代表B2:J10和B12:J20两个区域。用如下VBA程序清空初盘:Sub 清空初盘()

Dim rag As Range

For Each rag In Range("数独盘")

ragClearContents

ragFontBold = False

Next

End Sub

用如下VBA程序把初盘“粗体化”:Sub 粗体初盘()

Dim rag As Range

For Each rag In Range("数独盘")

If ragValue = "" Then

ragFontBold = False

Else

ragFontBold = True

End If

Next

End Sub为建“可选数”表,先用如下程序语句清空“可选数”区域:Range("可选数")ClearContents '清空可选数

以下程序段,作为解数独的初始化工作的一部分完成如下工作:在“数独盘”区域仅保留粗体的已知数作为初盘。在“可选数”区域的与“数独盘”已知数对应的单元格,抄录已知数,其他单元格取“123456789”。程序如下:For Each rag In Range("可选数")

If ragOffset(-10, 0)FontBold Then '“数独盘”中用粗体字表示已知数

ragValue = ragOffset(-10, 0)Value '把“数独盘”中的已知数抄录到对应的“可选数”区域中的相应位置

Else

ragValue = "123456789" '“数独盘”中的未知数在“可选数”区域中的相应位置设置成“123456789”

ragOffset(-10, 0)Value = "" '“数独盘”中的未知数用空格表示

End If

Next

接下来的初始化工作就是建立对应于初盘的可选数表。这部分工作和以后要讲的用“排除法”解数独题有相似之处。这些相似的工作用“处理确定数”子程序来完成。现在在“可选数”区域,寻找长度为1的数作为确定数,把该单元格置为空格,记下该单元格的行号和列号,由“处理确定数”子程序作相应处理。程序如下:For Each rag In Range("可选数")

If Len(ragValue) = 1 Then

qds = ragValue '已知数作为“确定数”

ragValue = "" '对应于“确定数”在“可选数”区域设为空格,表示无别的数可选

i% = ragRow - Range("可选数")Row + 1 '计算“确定数”在“可选数”区域的行号

j% = ragColumn - Range("可选数")Column + 1 '计算“确定数”在“可选数”区域的列号

Call 处理确定数(i%, j%, qds)

End If

Next

待续

开始的话:这个程序现在还不稳定,有时出现运行时错误,跟踪是由于vector的size()方法引起的。调试发现中间的min_seq并没有完全按照作者的意图变化。

运行时,如果出现错误,就反复运行,运行成功即可出现一个正确的99数独矩阵。

如果要玩预先填充一些数的游戏,只需修改初始矩阵即可。

算法:为每个位置定义一个可选元素集合,每个更新是把它所在的行,列,所在的3×3方阵中已出现的元素从集合中去掉。填充时,从最小候选集合中选一个(可随即)填进去,更新候选集合,再填充,直到所有位置填充完毕,游戏结束。

/9×9数独游戏的计算机程序/

/作者:xiaocui/

/时间:2006623/

/版本:v10/

/算法思想/

/对每个位置的元素,考虑其可选取的数字

的集合,每次把候选元素个数最小的那个位置填充

从该最小候选集合中随机选取一个元素填充,重复

这个过程,直到所有元素填充完毕/

/适用填充全空的数独方格 和 填充已有一些数的数独方格/

/对初始化的候选集的第一次更新正是为了解决第2类数独游戏/

/对于已填充一部分元素的,直接修改MATRIX矩阵即可/

/数独游戏的结果不止一种/

#include <iostream>

#include <ctime>

#include <vector>

using namespace std;

/初始9×9的矩阵/

/元素为0,说明该位置还未填充/

int MATRIX[9][9]={ {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} };

/初始给出的元素个数/

int INITIAL_COUNT;

/已填充元素个数,作为填充结束标志/

int FINISH_COUNT=0;

/各个元素的初始候选集合/

vector<vector<int> > IVEC(81);

/函数原型/

/得到初始给出的元素个数/

int get_initialcount();

/初始化候选集合/

void initial_candidate();

/从vector中删除指定元素/

void delete_value(vector<int> &ivec,int value);

/更新候选集合/

void refresh_candidate();

/返回9×9候选集合元素最少的候选集合序号/

int min_seq();

/随机生成一个位置序号并取得该序号所对应的元素值/

int choose_seq(int min_seq);

/填充该元素并判断是否填充完毕/

int is_finish(int min_seq, int choose_value);

int main()

{

/得到初始给出的元素个数/

INITIAL_COUNT=get_initialcount();

/初始化候选集合/

initial_candidate();

/先更新候选集合(为了应付已经填充一部分数的情况)/

refresh_candidate();

int i;

int MinSeq;

int ChooseValue;

MinSeq=min_seq();

ChooseValue=choose_seq(MinSeq);

while(is_finish(MinSeq,ChooseValue)!=1)

{

refresh_candidate();

MinSeq=min_seq();

ChooseValue=choose_seq(MinSeq);

}

/输出填好的数独游戏结果/

for( i=0;i<9;++i)

{

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

{

cout<<MATRIX[i][j]<<'\t';

}

cout<<endl;

}

return 0;

}

/函数定义/

/得到初始给出的元素个数/

int get_initialcount()

{

int count=0;

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

{

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

{

if(MATRIX[i][j]!=0)

{

count++;

}

}

}

return count;

}

/初始化候选集合/

void initial_candidate()

{

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

{

for(int j=1;j<10;++j)

{

IVEC[i]push_back(j);

}

}

}

/从vector中删除指定元素/

void delete_value(vector<int> &ivec,int value)

{

/如果ivec已经为空,直接退出/

if (ivecsize()==0)

{

return;

}

vector<int>::iterator iter=ivecbegin();

while( iter<ivecend() && (iter)!=value )

{

iter++;

}

if(iter<ivecend())//在vector中找到已填充的元素,把它删除

{

ivecerase(iter);

}

}

/更新候选集合/

void refresh_candidate()

{

int i;

int rownum,colnum;

int row,col;

/更新81个vector/

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

{

row=i/9;

col=i%9;

if(MATRIX[row][col]!=0)//该位置已经填充

{

if(IVEC[i]size()!=0)//该vector不空

{

/删除整个候选集/

IVEC[i]erase(IVEC[i]begin(),IVEC[i]end());

}

}

else

{

/删除同一行中的元素/

for(colnum=0;colnum<9;++colnum)

{

delete_value(IVEC[i],MATRIX[row][colnum]);

}

/删除同一列中的元素/

for(rownum=0;rownum<9;++rownum)

{

delete_value(IVEC[i],MATRIX[rownum][col]);

}

/删除在一个3×3方阵中的元素/

/在第1块中,删除3×3方阵元素/

if(row/3==0 && col/3==0)

{

for(int r=0;r<3;++r)

{

for(int c=0;c<3;++c)

{

delete_value(IVEC[i],MATRIX[r][c]);

}

}

}

/在第2块中,删除3×3方阵元素/

if(row/3==0 && col/3==1)

{

for(int r=0;r<3;++r)

{

for(int c=3;c<6;++c)

{

delete_value(IVEC[i],MATRIX[r][c]);

}

}

}

/在第3块中,删除3×3方阵元素/

if(row/3==0 && col/3==2)

{

for(int r=0;r<3;++r)

{

for(int c=6;c<9;++c)

{

delete_value(IVEC[i],MATRIX[r][c]);

}

}

}

/在第4块中,删除3×3方阵元素/

if(row/3==1 && col/3==0)

{

for(int r=3;r<6;++r)

{

for(int c=0;c<3;++c)

{

delete_value(IVEC[i],MATRIX[r][c]);

}

}

}

/在第5块中,删除3×3方阵元素/

if(row/3==1 && col/3==1)

{

for(int r=3;r<6;++r)

{

for(int c=3;c<6;++c)

{

delete_value(IVEC[i],MATRIX[r][c]);

}

}

}

/在第6块中,删除3×3方阵元素/

if(row/3==1 && col/3==2)

{

for(int r=3;r<6;++r)

{

for(int c=6;c<9;++c)

{

delete_value(IVEC[i],MATRIX[r][c]);

}

}

}

/在第7块中,删除3×3方阵元素/

if(row/3==2 && col/3==0)

{

for(int r=6;r<9;++r)

{

for(int c=0;c<3;++c)

{

delete_value(IVEC[i],MATRIX[r][c]);

}

}

}

/在第8块中,删除3×3方阵元素/

if(row/3==2 && col/3==1)

{

for(int r=6;r<9;++r)

{

for(int c=3;c<6;++c)

{

delete_value(IVEC[i],MATRIX[r][c]);

}

}

}

/在第9块中,删除3×3方阵元素/

if(row/3==2 && col/3==2)

{

for(int r=6;r<9;++r)

{

for(int c=6;c<9;++c)

{

delete_value(IVEC[i],MATRIX[r][c]);

}

}

}

}

}

}

/返回9×9候选集合元素最少的候选集合序号/

int min_seq()

{

int count[81];

int i;

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

{

count[i]=IVEC[i]size();

}

int value=10;

int min_seq;

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

{

if(count[i]==0)

{

continue;

}

if(count[i]<value)

{

value=count[i];

min_seq=i;

}

}

return min_seq;

}

/随机生成一个位置序号并取得该序号所对应的元素值/

int choose_seq(int min_seq)

{

/根据当前时间设置种子/

srand((unsigned)time( NULL ));

int random_seq=rand()%(IVEC[min_seq]size());

return IVEC[min_seq][random_seq];

}

/填充该元素并判断是否填充完毕/

int is_finish(int min_seq, int choose_value)

{

int row, column;

row=min_seq/9;

column=min_seq%9;

MATRIX[row][column]=choose_value;

FINISH_COUNT++; /已填充元素个数加1/

/填充完毕判断/

if(FINISH_COUNT==81-INITIAL_COUNT)

{

return 1;

}

else

{

return 0;

}

}

>

以上就是关于数独是如何计算的全部的内容,包括:数独是如何计算的、用VBA解数独程序、数独设计思路及全解等相关内容解答,如果想了解更多相关内容,可以关注我们,你们的支持是我们更新的动力!

欢迎分享,转载请注明来源:内存溢出

原文地址: https://outofmemory.cn/zz/10133641.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2023-05-05
下一篇 2023-05-05

发表评论

登录后才能评论

评论列表(0条)

保存