【问题标题】:Recursive Backtracking Sudoku Solver Problems, c++递归回溯数独求解器问题,c++
【发布时间】:2011-10-24 14:05:21
【问题描述】:

这是我第一次在低级课程中将递归作为作业处理。我浏览了互联网,似乎找不到任何人使用与我想出的方法类似的方法(这可能说明了为什么这不起作用)。该错误是std::__copy_move... 中的分段错误,我假设它是c++ STL 中的内容。 Anywho,我的代码如下:

bool sudoku::valid(int x, int y, int value)
{
    if (x < 0) {cerr << "No valid values exist./n";}

    if (binary_search(row(x).begin(), row(x).end(), value))
        {return false;}                 //if found in row x, exit, otherwise:
    else if (binary_search(col(y).begin(), col(y).end(), value))
        {return false;}                 //if found in col y, exit, otherwise:
    else if (binary_search(box((x/3), (y/3)).begin(), box((x/3), (y/3)).end(), value))
        {return false;}                 //if found in box x,y, exit, otherwise:
    else
        {return true;}                  //the value is valid at this index
}

int sudoku::setval(int x, int y, int val)
{
    if (y < 0 && x > 0) {x--; y = 9;}   //if y gets decremented past 0 go to previous row.
    if (y > 8) {y %= 9; x++;}           //if y get incremented past 8 go to next row.

    if (x == 9) {return 0;}             //base case, puzzle done.
    else {
        if (valid(x,y,val)){            //if the input is valid
            matrix[x][y] = val;         //set the element equal to val
            setval(x,y++,val);          //go to next element
        }
        else {
            setval(x,y,val++);          //otherwise increment val
            if(val > 9) {val = value(x,y--); setval(x,y--,val++); }
        }                               //if val gets above 9, set val to prev element,  
    }                                   //and increment the last element until valid and start over
}

我一直在努力解决这个问题,但我似乎无法弄清楚出了什么问题。任何建议都非常感谢! :)

【问题讨论】:

  • matrix 是什么?在不了解此类细节的情况下,很难为您调试代码。
  • 我认为你应该重新审视算法设计。在递归的if 部分中,您在递归之前检查有效性,在else 部分中,您不进行有效性检查。此外,您仅在递归之后检查val &gt; 9
  • 首先写下 setval 的作用。特别想: if (!valid(x,y,val)) setval 尝试在其他 (x,y) 对中一次又一次地分配 val,但是如果它对任何 (x,y) 都无效怎么办?
  • @awoodland:没有人能告诉你matrix是什么...

标签: c++ recursion backtracking


【解决方案1】:

sudoku::setval 应该返回int,但至少有两条路径根本不返回任何内容。您应该弄清楚它需要在其他路径中返回什么,否则您将获得随机的未定义行为。

【讨论】:

    【解决方案2】:

    如果没有更多信息,就无法判断。数据之类的东西 例如,所涉及的结构,以及 rowcol 返回的内容。 尽管如此,还是有一些明显的问题:

    • sudoku::valid 中,检查明显错误的内容 条件(x &lt; 0),但您不返回;你仍然继续你的 测试,使用x 的负值。

    • 同样在sudoku:valid:做rowcol真的返回引用 排序值?如果值未排序,则 binary_search 将 具有未定义的行为(如果是,则名称有些 误导)。如果它们返回值(某些东西的副本),而不是 比对同一对象的引用,然后是 begin()end() 函数将引用不同的对象——同样,未定义 行为。

    • 最后,我在您的算法中看不到任何回溯,我也没有 看看它是如何发展成解决方案的。

    FWIW:当我写类似的东西时,我使用了一个简单的 81 数组 板的元素,然后创建映射的静态数组 索引 (0-80) 到适当的行、列和框。并且对于每个 九行、列和框,我保留了一组使用过的值(a 位图);这使得合法性检查变得非常简单,这意味着 我可以通过增加 指数。生成的代码非常简单。

    独立于所使用的数据表示,您需要:一些 “全球”(可能是sudoku 的成员)意味着知道您是否已经 是否找到解决方案;在某处尝试九个中的每一个的循环 正方形的可能值(当解已经 找到)和递归。如果您没有使用简单的数组 板,就像我所做的那样,我建议为索引设置一个类或结构,并带有 一劳永逸地处理增量的函数。

    【讨论】:

      【解决方案3】:

      以下所有内容均适用于 Unix 而不是 Windows。

      std::__copy_move... STL 没问题。但是 STL 本身不会做任何事情,您的代码中的某些函数调用会使用错误的参数或处于错误的状态来调用它。你需要弄清楚这一点。

      如果您有来自 teh seg-fault 的核心转储,那么只需执行 pstack &lt;core file name&gt;,您将看到崩溃的完整调用堆栈。然后只需查看您的代码的哪一部分参与其中并从那里开始调试(添加跟踪/couts/...)。

      通常你会得到这个具有可读性好名称的核心文件,但如果你不这样做,你可以使用nmc++filt 等来命名dismangle

      最后,pstack 只是一个小型命令行实用程序,您始终可以将二进制文件(生成内核的)和内核文件加载到调试器中,例如 gdbSun Studio 或内置在您的 IDE 中的调试器和看到同样的事情以及许多其他信息和选项。

      HTH

      【讨论】:

        【解决方案4】:

        您的算法似乎有点“蛮力”。对于约束满足问题 (CSP),这通常不是一个好的策略。不久前我写了一个数独求解器(希望我还有源代码,那是在我发现 github 之前),我能找到的最快的算法是模拟退火:

        http://en.wikipedia.org/wiki/Simulated_annealing

        它是概率性的,但对于这个问题 IIRC,它通常比其他方法快几个数量级。

        HTH!

        【讨论】:

          【解决方案5】:

          如果您以递归方式多次输入函数,则可能(并且将会)发生分段错误。 我注意到导致它的一种情况。但我很确定还有更多。

          提示:用你的话写出任何函数的目的——如果写得太复杂——函数可能应该被拆分...

          【讨论】: