您的位置:首页 > 其它

数独游戏(sudoku)算法 回溯+剪枝

2011-05-08 16:09 453 查看
具体数独游戏是什么,我就不介绍了,好像多余了,你能来看这篇文章,说明你对数独游戏已经有了相当的了解了!还是入正题吧,今天先讲解和发下用回溯+剪枝 求数独游戏,我也看了些回溯+剪枝求数独的算法,很恼火,既没注释,而且算法没有通用性。

今天我给大家讲的回溯+剪枝法,不仅可以用于解决数独问题,而且还可以方便用于其他难题。

先介绍回溯+剪枝法吧:回溯+剪枝

可以这样说 回溯+剪枝 法是解决一般性难题的很好的方法,当然如果难题的规模太大的话,计算机内存和运行时间,可能就超出你的范围了。

回溯法就是在问题的解空间中搜索满足条件的解。

要使用回溯法:需理解三个问题(我的理解)

1、怎样构造解空间

2、在什么条件下回,即剪枝的条件

3、回到哪个节点

在类CGrid中定义静态函数如下

static BOOL IsSingleInRow(int num,int row,int grid[9][9]);

//判断数num 在行row 中是否唯一
static BOOL IsSingleInColumn(int num, int colunm, int grid[9][9]);

//判断数num 在列column 中是否唯一
static BOOL IsSingleGongge(int num,int row,int column,int grid[9][9]);

//判断数num 在行row ,列column所在的子宫格中是否唯一
上面的几个函数,非常非常的简单,即不写了,但在函数GetAllResult中 会被用到

下面主要看GetAllResult是怎么写的哦,这个函数是要求出所有的解哦,并存在filename指定的文件中
static BOOL GetAllResult(int grid[][9], CString filename);//filename 用于存储所有的结果

对了,还有个结构体,非常的重要,用于存储空格的相关信息

struct Blank
{
int row; //空格所在的行
int column; //空格所在的列
int candidate_num; //空格中候选数的个数
int startindex; //标示下次应选择哪个候选数
int candidate[9]; //记录下候选数

};

BOOL CGrid::GetAllResult(int grid[][9], CString filename)
{
int i,j,k;
int blank_num=0; //空格的个数
int candidate_num; //空格中的候选数 个数
int result_num=0; //解的个数

int tryGrid[9][9]j;
struct Blank blank[81]; //空格结构体,最大为81个空格

//求出所有的空格,并同时初始的布局赋值给tryGrid
for (i=0;i<9;i++)
{
for (j=0;j<9;j++)
{
tryGrid[i][j]=grid[i][j];

if (grid[i][j] == 0) //表示空格
{
blank[blank_num].row=i; //记录行号
blank[blank_num].column=j; //记录列号
blank[blank_num].startindex=0;

//标示:下次应选择第几个候选数,初始化为0,第一次选择0这个位置

candidate_num=0;
for (k=1;k<=9;k++)
{
if ( CGrid::IsSingleInRow(k,i,grid)
&& CGrid::IsSingleInColumn(k,j,grid)
&& CGrid::IsSingleGongge(k,i,j,grid))
{
blank[blank_num].candidate[candidate_num++] = k;
}
}

blank[blank_num].candidate_num = candidate_num; //候选数个数

blank_num++; //空格数加1

}
}

}

int tempnum;
int succeed=0; //标示这次选择是否选出了合法的候选数

int node_index=0; //表示节点
int new_node_index=-1;

while (TRUE)
{

succeed=0; //每次选的时候初始化为0
while ( blank[node_index].startindex < blank[node_index].candidate_num)
{
tempnum=blank[node_index].candidate[blank[node_index].startindex];
//从空格i中取的第blank[i].startindex个候选数,
//看是否与已经填的方格冲突,且blank[i].startindex<blank[i].candidate_num

if (CGrid::IsSingleInRow(tempnum,blank[node_index].row,tryGrid)
&& CGrid::IsSingleInColumn(tempnum,blank[node_index].column,tryGrid)
&& CGrid::IsSingleGongge(tempnum,blank[node_index].row,blank[node_index].column,tryGrid))
{
tryGrid[blank[node_index].row][blank[node_index].column] = tempnum; //满足3个条件,填入方格的空格中
succeed = 1;
blank[node_index].startindex++;
node_index++; //选择下一个节点中的候选数
break;
}
else
{
blank[node_index].startindex++;

}

}

//succeed==0 标示这次没选成功,一个都不合法,就回啊

//如果我们发现方格i中的所有候选数均不能满足条件,说明以前的选择有误,
//应重新选择以前空格中的候选数,
//空格下面的p满足condition_12:1、空格还有候选数可选;2、该空格距离当前的空格最近

// cout<<node_index-1<<". "<<blank[node_index-1].startindex-1<<" | ";

if (succeed==0) //succeed==0 标示这次没选成功,一个候选数都不合法
{
//找出满足condition_12 空格p
new_node_index=-1;
for (int p=node_index;p>=0;p--)
{
if ( blank[p].startindex < blank[p].candidate_num )
{
new_node_index=p;
break;
}
}

if (new_node_index==-1) //p==-1表明所有空格均不满足condition_12
{
// AfxMessageBox("无解");
//把结果输出到文件
if (result_num==0)
//cout<<endl<<"no result"<<endl;
CGrid::OutputToFileNoResult(filename);

//这个函数的作用是输出结果,可以自己写,或者你可以输出到控制台上
else
cout<<endl<<result_num<<endl;

return FALSE;
}

//撤销操作
for (int q=new_node_index+1;q <=node_index;q++)
{
tryGrid[blank[q].row][blank[q].column]=0;
blank[q].startindex=0;

}

node_index=new_node_index; //回到p处 重新选择下一个候选数

}

//succeed==1,表示再根节点处找到了合法的候选数
//node_index==blank_num-1 表示已经搜索跟节点,

if (succeed==1 && node_index==blank_num)
{
result_num++;
CGrid::DIsplay(tryGrid);//显示找到的解
//这个函数的作用是输出结果,可以自己写

// 继续找下一个解

new_node_index=-1;
for (int p=node_index-2;p>=0;p--)
{
if ( blank[p].startindex < blank[p].candidate_num )
{
new_node_index=p;
break;
}
}

if (new_node_index==-1) //p==-1表明所有空格均不满足condition_12
{
AfxMessageBox("无更多解");

return FALSE;
}

//撤销操作
for (int q=new_node_index+1;q<node_index;q++)
{
tryGrid[blank[q].row][blank[q].column]=0;
blank[q].startindex=0;

}

node_index = new_node_index; //回到p处 重新选择下一个候选数

}

}

return TRUE;

}

自我评价:程序可读性不好!程序的性能可能不是很好!欢迎拍砖。

第一次在CSDN写文章,写的不好!
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: