【问题标题】:Recursive Sudoku Solver- Segmentation Fault (C++)递归数独求解器 - 分段错误 (C++)
【发布时间】:2012-07-25 08:24:41
【问题描述】:

为了学习使用递归,我正在尝试制作数独求解器。我似乎已经让大部分代码可以很好地协同工作,但是当我运行程序时,我收到一个 Windows 错误,告诉我程序已停止工作。调试表明存在分段错误,我在其他地方看到这可能是由太多递归引起的。我知道这是一种蛮力方法,但同样,我更担心让它发挥作用而不是速度。我可以做些什么来解决这个问题?

struct Playing_grid {
    //Value of cell
    int number;
    //wether the number was a clue or not
    bool fixed;
}
grid[9][9];

    void recursiveTest(int row, int column, int testing)
    {
    //first, check to make sure it's not fixed
        if(grid[row][column].fixed == false)
        {
            if((checkRow(testing, row) | checkColumn(testing, column) | checkBox(testing,boxNumber(row,column)) | (testing > 9)) == 0)
            {
                grid[row][column].number = testing;
                moveForward(row,column,testing);
                recursiveTest(row, column, testing);
            }
            else if(testing < 9)
            {
                testing ++;
                recursiveTest(row, column, testing);
            }
            else if(testing == 9)
            {
                while(testing == 9)
               {
                moveBack(row,column,testing);
                while(grid[row][column].fixed == true)
                {
                    {
                        moveBack(row,column,test);
                    }
                }
                testing = grid[row][column].number;
                recursiveTest(row,column,testing);
               }
            }
        }
        else
        {
            moveForward(row,column,testing);
            recursiveTest(row,column,testing);
        }
    }



     void moveForward(int& row, int& column, int& test)
{
    if(column < 8)
    {
        column ++;
    }
    else if((column == 8) & (row != 8))
    {
        column = 0;
        row ++;
    }
    else if((column == 8) & (row == 8))
    {
        finishProgram();
    }
    test = 1;
}

    void moveBack(int& row, int& column, int& test)
    {
        grid[row][column].number = 0;
        if(column > 0)
            {
                column --;
            }
        else if((column == 0) & (row > -1))
            {
                column = 8;
                row --;
            }
        else
        {
            cout << "This puzzle is unsolveable!" << endl;
        }
        test++;
    }

我试图包含所有相关的部分。我基本上创建了一个 9x9 矩阵,此时它填充了 81 个值,其中空槽写为 0。确认测试值在行、列和框中有效后,它填充该值并移动到下一个空间。每当它运行到 9 并且没有可能的值时,它就会返回到前一个值并遍历那个值。

为了不覆盖已知值,递归函数每次都会检查 grid[row][column].fixed 的值是否为 false。

对于清理、浓缩等方面的任何见解,我将不胜感激。提前致谢!

编辑:要退出递归循环,当调用函数向前移动时,如果它已到达最后一个单元格,则完成(保存+输出)解决方案。已对代码进行了调整以反映这一点。

【问题讨论】:

  • 你的调试器告诉你你的分段错误是什么?
  • 我不熟悉 C(我假设是这样),但作为伪代码快速浏览一下,您的算法似乎有缺陷。我看不到通过 recursiveTest 本身不调用 recursiveTest 的方法,这意味着它将无限递归。您需要让一些调用完成,以便它们可以脱离堆栈。作为一般规则,我希望 moveBack 只在一个单元格之后直接调用到 recursiveTest ;在 while 循环中不重复。
  • 我得到的关于分段错误的所有信息都是“程序收到信号 SIGSEGV,分段错误”消息。我不知道如何获取有关该消息的更多信息。我忘记在 moveForward 循环中实现一个部分 - 当它到达网格中的最后一个空间 (8,8) 并且它是有效的时,我让它保存并输出完成的拼图。此外,while 循环会检查前一个单元格的固定值,并继续检查直到达到未知值。

标签: recursion segmentation-fault sudoku


【解决方案1】:

我通常会尝试修复您的代码,但我认为在这种情况下它存在根本缺陷,您需要重新设计。

一般来说,像这样的递归函数的伪代码是

For each possible (immediate) move
  Perform that move
  Check for win state, if so store/output it and return true.
  Call this function. If it returns true then a win state has been found so return true 
  Otherwise unperform the move
Having tried every move without finding a win state, return false.

【讨论】:

  • 这基本上是你所说的我的(感知的)版本 - 但是,我找不到一个“不执行”移动的好方法,这就是它变得如此混乱的原因。撤消/进入先前状态的好方法是什么?
  • @BenjaminGoodberry 将您的“光标”移回前一个单元格是撤消移动的一种完全合理的方式,但是通常您的代码甚至不像我在这里提出的那样远程结构化。我真的会删除该函数中的所有代码并重新开始。另外,删除测试参数;当您检查每个可用的移动时,这就是您应该循环的内容。就我个人而言,我也会删除 x 和 y 并将它们作为类的属性,但这只是个人偏好。
  • (顺便去睡觉了,所以如果我不快点回复不是因为我不理你,我会在早上回来查看)
猜你喜欢
  • 1970-01-01
  • 2017-06-05
  • 2018-03-30
  • 2017-12-16
  • 2017-02-11
  • 2016-08-16
  • 1970-01-01
  • 1970-01-01
  • 2019-02-21
相关资源
最近更新 更多