递归回溯数独求解器问题,c ++

时间:2011-10-24 14:05:21

标签: c++ recursion backtracking

这是我第一次在低级课程中处理递归作为一项任务。我环顾了互联网,我似乎找不到任何人使用类似于我提出的方法(这可能说明了为什么这不起作用)。错误是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
}

我一直想把这个东西包围一段时间,我似乎无法弄清楚出了什么问题。任何建议都非常感谢! :)

5 个答案:

答案 0 :(得分:1)

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

答案 1 :(得分:1)

没有更多信息,就无法分辨。像数据这样的东西 例如,涉及的结构以及rowcol返回的内容。 仍然存在许多明显的问题:

  • sudoku::valid中,您可以检查显然是错误的内容 条件(x < 0),但你没有回来;你仍然继续你的 测试,使用x的负值。

  • 同样在sudoku:validrowcol确实返回了对 排序值?如果值未排序,那么binary_search将会 有未定义的行为(如果它们是,名称有点 误导)。如果他们返回值(某些东西的副本),而不是 而不是对同一个对象的引用,那么begin()end() 函数将引用不同的对象 - 再次,undefined 行为。

  • 最后,我没有看到你的算法有任何回溯,我没有 看看它如何发展成为一个解决方案。

FWIW:当我写了类似的东西时,我使用了81的简单数组 电路板的元素,然后创建映射的静态数组 索引(0-80)到适当的行,列和框。并为每一个 九行,列和框,我保留了一组使用过的值(a 位图);这使得检查合法性非常微不足道,这意味着 我可以通过递增来增加到下一个方格来测试 指数。结果代码非常简单。

无论使用何种数据表示,您都需要:一些 “全球”(可能是sudoku的成员)意味着知道你是否已经 找到了解决方案;尝试九个中的每一个的某个循环 正方形的可能值(解决方案已停止时停止) 发现)和递归。如果你没有使用简单的数组 像我一样,我建议索引的类或结构,用 一劳永逸地处理增量的功能。

答案 2 :(得分:0)

以下所有内容适用于Unix而非Windows。

std::__copy_move...是STL好的。但是STL本身并没有做任何事情,你的代码中的某些函数调用会用错误的参数或错误的状态调用它。你需要明白这一点。

如果您有来自teh seg-fault的核心转储,那么只需执行pstack <core file name>,您将看到崩溃的完整调用堆栈。然后只需看看代码中涉及哪部分代码并从那里开始调试(添加trace / couts / ...)。

通常你会得到这个具有良好可读名称的核心文件,但如果你没有,你可以使用nmc++filt等来dismangle这些名称。

最后,pstack只是一个小的cmd行实用程序,您始终可以将二进制文件(生成核心)和核心文件加载到gdbSun Studio之类的调试器或调试器内置于您的IDE中,并查看相同的内容以及许多其他信息和选项。

HTH

答案 3 :(得分:0)

如果以递归方式输入函数次数太多,

分段错误可能会(并且会发生)。 我注意到一个导致它的情景。但我很确定还有更多。

提示:在你的文字中写下任何函数的目的 - 如果它写得太复杂 - 函数应该被拆分......

答案 4 :(得分:0)

看起来你的算法有点“暴力”。这通常不是约束满意度问题(CSP)的好策略。我曾经写过一个数独求解器(希望我还有源代码,它是在我发现github之前),我能找到的最快算法是模拟退火:

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

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

HTH!