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

Recursive Backtracking Sudoku Solver Problems, c++

本文关键字:问题 c++ 回溯 递归      更新时间:2023-10-16

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

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
}
我一直想把我的头绕在这件事上一段时间,但我似乎不知道出了什么问题。任何建议都非常感谢!:)

sudoku::setval应该返回一个int,但至少有两个路径它什么也不返回。你应该弄清楚它在其他路径中需要返回什么,否则你会得到随机的未定义行为

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

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

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

  • 最后,我在你的算法中没有看到任何回溯,我也没有

顺便说一句:当我写类似的东西时,我使用了一个简单的81数组元素,然后创建静态数组来映射索引(0–80)到适当的行、列和框。对于每一个在九行、九列和九框中,我保存了一组使用值(a位图);这使得检查合法性变得微不足道,这意味着我可以增加到下一个平方来测试只需要增加索引。生成的代码非常简单。

与使用的数据表示无关,您将需要:some"global"(可能是sudoku的成员)意味着知道您是否已经是否找到了解决方案;在某个地方循环尝试每一个一个正方形的可能值(当解已经find)和递归。如果不使用简单数组board,就像我做的那样,我建议为索引使用一个类或结构函数,一次性处理增量

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

std::__copy_move...是STL正确的。但STL本身不会做任何事情,代码中的一些函数调用会用错误的参数或错误的状态调用它。你得想清楚。

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

通常你会得到这个核心文件与良好的可读性名称,但如果你不你可以使用nmc++filt等拆除名称。

最后,pstack只是一个小的cmd行实用程序,您可以随时将二进制文件(产生核心)和核心文件加载到调试器中,如gdb, Sun Studio或调试器内置到您的IDE中,并看到与许多其他信息和选项相同的东西。

HTH

看起来你的算法有点"蛮力"。这通常不是约束满足问题(csp)的好策略。我写了一个数独解算器(希望我仍然有源代码,这是在我发现github之前),我能找到的最快的算法是模拟退火:

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

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

HTH !

如果多次递归地输入一个函数,可能(也将)发生分段错误。我注意到导致这种情况的一个场景。但我敢肯定还有更多。

提示:用你的语言写出任何函数的目的——如果它太复杂而写不出来——函数可能应该被拆分…