回溯法解数独题

近段时间用到回溯算法的地方比较多,对算法的理解也有深入。今天偶然发现一张照片,是高中时未做完的一道数独题。当时用的是“候选余数法”,之后由于太麻烦,就没有做完。不过当时截图保存了,今天突然看到。那时候刚学完C语言,对汉诺塔递归都不是太理解,所以就一直拖到现在。

用C++做的,代码如下

#include<iostream>
usingnamespace std;
 
intsudoku[9][9]={0};
 
//判断填在空白位置的数字在行、列上是否符合要求
boolJudge1(int x, int y, int n)
{
            int i;
           
            for(i=0;i<9;i++)
            {
                        //判断 列
                        if((sudoku[i][y]==n)&& (i!=x))
                                    returnfalse;
                        //判断 行
                        if((sudoku[x][i]==n)&& (i!=y))
                                    returnfalse;
            }
 
            return true;
}
 
//判断填在空白位置的数字在九宫格之内是否符合要求
boolJudge2(int x, int y, int n)
{
            int xx,yy,i,j;
            xx=x/3;
            yy=y/3;
            for(i=xx*3;i<xx*3+3;i++)
                        for(j=yy*3;j<yy*3+3;j++)
                                    if(sudoku[i][j]==n)
                                                if(i==x&& j==y)
                                                            continue;
                                                else
                                                            returnfalse;
            return true;
}
 
//填充空白数组
boolFill(int m)
{
            int n,x,y;
            x=m/9;
            y=m%9;
            if (m>=81)
                        return true;
            if (sudoku[x][y]==0)
            {
                        for(n=1;n<=9;n++)
                        {
                                    sudoku[x][y]=n;
                                    if(Judge1(x,y,n)&&Judge2(x,y,n))
                                                if(Fill(m+1))
                                                            returntrue;
                                    sudoku[x][y]=0;
                                               
                        }
            }
            else
                        return Fill(m+1);
 
            return false;
}
 
intmain()
{
            //输入初始数独
            int i,j,k;
            cout << "输入初始数独数据,空白用0代替" <<endl;
            for(i=0;i<9;i++)
                        for(j=0;j<9;j++)
                                    cin>>sudoku[i][j];
           
            /*for(i=0;i<9;i++)
            {
                        for(j=0;j<9;j++)
                                    cout<< sudoku[i][j] << " ";
                        cout << endl;
            }*/
 
           
            if(Fill(0))//填充数独的空白位置完毕
            {
                        for(i=0;i<9;i++)
                        {
                                    for(j=0;j<9;j++)
                                    {
                                                cout<< sudoku[i][j] << " ";
                                                if(!((j+1)%3))
                                                            cout<< "| ";
                                    }
                                    cout<< endl;
                                    if(!((i+1)%3))
                                    {
                                                for(k=0;k<12;k++)
                                                            cout<<"__";
                                                cout<< endl;
                                    }
                        }
 
            }
            else
                        cout << "该数独无解,请注意游戏规则或检查原始数独是否有误" << endl;
 
            return 0;
}

运行之后的截图

时间: 2024-10-13 16:17:32

回溯法解数独题的相关文章

回溯法求解数独算法(C语言)

没有对输入的待解数独进行一般性验证(同一行.一列以及同一个小九宫格都不能出现重复数字) 算法利用回溯的思想: 从第一个空白处开始,找到其候选解(排除同行.同列以及同一小九宫格的所有出现过的数字,剩下未出现的数字都是候选解)的第一个值填入数独. 对第二个空白执行第一步(前面所填入的数字对此空白处有影响). 当出现某个空白的候选解个数为0时,就开始回溯,找到第一个候选解多于一个的,将其在使用的候选解设为不可取(本程序取值为-1),找到其下一个候选解,继续上面的步骤! 直到所有空白处填满,运算完成,输

回溯法第7题—圆盘移动问题

[问题描述]从左向右依次安放4根细柱A,B,C,D.在A柱上套有n(n<=20)个直径相同的圆盘,从上到下一次用连续的小写字母a,b,c,...编号,将这些圆盘经过B,C单向的移动到D柱上(即不允许从右向左移动.圆盘可在B,C中暂存).要求找到从A柱初始状态到D柱目标状态的移动过程.输入:第一行是D柱上的圆盘总数,第二行是D柱上由下到上的圆盘的序列.输出:是一个文件.该文件的每一行为一个形如"k m l"的字母序列,其中k为圆盘编号,m为k盘原先的柱号,l为目标柱号.如果不能生成

回溯法第7题&mdash;圆盘移动问题

[问题描述]从左向右依次安放4根细柱A,B,C,D.在A柱上套有n(n<=20)个直径相同的圆盘,从上到下一次用连续的小写字母a,b,c,...编号,将这些圆盘经过B,C单向的移动到D柱上(即不允许从右向左移动.圆盘可在B,C中暂存).要求找到从A柱初始状态到D柱目标状态的移动过程.输入:第一行是D柱上的圆盘总数,第二行是D柱上由下到上的圆盘的序列.输出:是一个文件.该文件的每一行为一个形如"k m l"的字母序列,其中k为圆盘编号,m为k盘原先的柱号,l为目标柱号.如果不能生成

回溯法第3题—n皇后问题

[问题描述] 在一个国际棋盘上,放置n个皇后(n<10),使她们相互之间不能进攻.求出所有布局. 输入:n 输出:每行输出一种方案,每种方案顺序输出皇后所在的列号,每个数之间用空格隔开. [样例输入] 4 [样例输出] 2 4 1 3 2 1 4 2 [问题分析] 我想这大概是回溯法最经典的一个问题了吧,开一个函数判断一下当前位置是否能放即可. 这里有一个小技巧,就是对皇后进行编号,对应着数组的下标,就可以很容易的满足第一个条件——所有皇后不能在同一行上. 然后数组元素则代表皇后所在的列数,满足

回溯法第4题&mdash;置棋问题

[问题描述] 在m*n的主格中任意指定x个格子构成一个棋盘,在任一个构成的棋盘上放置k个棋子,要求任意两个棋子不得位于同一行或同一列上,要求输出满足条件的所有方案.(注意棋盘是稀疏的,即x<m*n/2.1<m,n<10). 编程要求: 1.对给定的一个棋盘,求出该棋盘可放置的最多的棋子数p. 2.记di为该棋盘上放置i个棋子时的方案总数(1<i<p),其中经旋转和镜面反射而得的方案记为不同方案,对每一个i,求出相应的di. 3.程序应能够连续处理多个棋盘,对每一个棋盘,输出p

回溯法第2题—邮票问题

[问题描述] 设有已知面额的邮票m种,每种有n张.问:用总数不超过n张的邮票进行组合,能组合的邮票面额中可以连续出现的面额数最多有多少? (1<=m<=100,1<=n<=100,1<=邮票面额<=225) 输入:第一行:n和m的值,中间用一空格隔开. 第二行:a[1..m](面额),每个数中间用一空格隔开.输出:连续面额数的最大值 [样例输入] 4 3 1 2 4 [样例输出] 14 [问题分析] 我写的程序 var a:array[0..100]of integer

回溯法第1题—数字排列问题

[问题描述] 列出所有从数字1到数字n的连续自然数的排列,要求所产生的任一数字序列中不允许出现重复的数字. 输入:n(1<=n<=9) 输出:由1~n组成的所有不重复的数字序列,每行一个序列. [样例输入] 3 [样例输出] 1 2 3 1 3 2 2 1 3 2 3 1 3 1 2 3 2 1 [问题分析] 这题要求输出n个数的全排列(从n个不同元素中任取m(m≤n)个元素,按照一定的顺序排列起来,叫做从n个不同元素中取出m个元素的一个排列.当m=n时所有的排列情况叫全排列). 显然也没有什

回溯法解背包问题分析

先亮出题目: 一,背包问题 及 回溯法解其问题的伪代码 二,赋值后的具体实例 三,如何看懂伪代码 (1)真正了解回溯法的核心思想 我总结的回溯法解题步骤: <1>先找出第一个解 <2>回溯 (2)回溯法核心思想 + 伪代码 + 图9-5 树结构来分析 四,伪代码代入值解析 核心:先找到第一个解,再回溯. cw=0;//背包当前重量 初始值 cp=0;//背包当前价值 初始值 k=1;//第一个物品 n=8;//共8个物品 W=110 第一步:得出第1个可行解: (1)k=1 k=1

回溯法第6题&mdash;0/1字符串问题

[问题描述]输入仅由0/1组成的长度为n的字符串,并且其中不可含有三个连续的相同子串. 输入:字符串的长度n(n<=40). 输出:所有满足条件的字符串的个数[样例输入] 2 [样例输出] 4 [问题分析]设0/1序列的长度为L,x,y,z分别为第三.第二.第一个子串的首指针:初始:x=L;y=L-1;z=L-2;若三个数字不同,dec(x,1);dec(y,2);dec(z,3);直到 (a[z]...a[y-1]=a[y]...a[x-1]=a[x]...a[l]) or (z<=0)再开