C++ - 解决数独游戏

发布于 2024-12-19 13:56:51 字数 1920 浏览 1 评论 0原文

我是 C++ 新手,必须做家庭作业(数独)。我被一个问题困住了。

问题是实现一个搜索功能来解决数独。

操作说明: 为了找到解决方案,使用递归搜索如下。假设有一个 尚未分配数字字段 (d1...dn) (n > 1)。然后我们首先尝试 将字段分配给d1,执行传播,然后继续搜索 递归地。 可能发生的情况是传播导致失败(一个场变成 空的)。在这种情况下,搜索会失败,需要尝试不同的数字之一 田野。由于搜索是递归的,因此最后考虑的字段的下一个数字 已尝试。如果没有一个数字能找到答案,搜索将再次失败。这在 转将导致尝试与前一个字段不同的数字,依此类推。

在通过将字段分配给尝试数字 d 之前 它,你必须创建一个新板作为当前板的副本(使用 复制构造函数并使用 new 从堆中分配板)。仅有的 然后在副本上执行分配。如果递归调用search 返回不成功,可以为下一个数字创建一个新板 尝试过。

我尝试过:

// Search for a solution, returns NULL if no solution found
Board* Board::search(void) {
    // create a copy of the cur. board
    Board *copyBoard = new Board(*this);
    Board b = *copyBoard;

    for(int i = 0; i < 9; i++){
        for(int j = 0; j < 9; j++){

              //  if the field has not been assigned, assign it with a digit 
            if(!b.fs[i][j].assigned()){
                digit d = 1;

                     // try another digit if failed to assign (1 to 9)
                while (d <=9 && b.assign(i, j, d) == false){
                        d++;


                      // if no digit matches, here is the problem, how to 
                      // get back to the previous field and try another digit?
                      // and return null if there's no pervious field 
                if(d == 10){
                      ...
                    return NULL;
                }
            }
        }
    }
    return copyBoard;
 }

另一个问题是在哪里使用递归调用?有什么建议吗?谢谢!

完整的说明可以在这里找到:http ://www.kth.se/polopoly_fs/1.136980!/Menu/general/column-content/attachment/2-2.pdf

代码: http://www.kth。 se/polopoly_fs/1.136981!/Menu/general/column-content/attachment/2-2.zip

I'm new to C++ and have to do a home assignment (sudoku). I'm stuck on a problem.

Problem is that to implement a search function which to solve a sudoku.

Instruction:
In order to find a solution recursive search is used as follows. Suppose that there is a
not yet assigned field with digits (d1....dn) (n > 1). Then we first try to
assign the field to d1, perform propagation, and then continue with search
recursively.
What can happen is that propagation results in failure (a field becomes
empty). In that case search fails and needs to try different digits for one of
the fields. As search is recursive, a next digit for the field considered last
is tried. If none of the digits lead to a solution, search fails again. This in
turn will lead to trying a different digit from the previous field, and so on.

Before a digit d is tried by assigning a field to
it, you have to create a new board being a copy of the current board (use
the copy constructor and allocate the board from the heap with new). Only
then perform the assignment on the copy. If the recursive call to search
returns unsuccessfully, a new board can be created for the next digit to be
tried.

I've tried:

// Search for a solution, returns NULL if no solution found
Board* Board::search(void) {
    // create a copy of the cur. board
    Board *copyBoard = new Board(*this);
    Board b = *copyBoard;

    for(int i = 0; i < 9; i++){
        for(int j = 0; j < 9; j++){

              //  if the field has not been assigned, assign it with a digit 
            if(!b.fs[i][j].assigned()){
                digit d = 1;

                     // try another digit if failed to assign (1 to 9)
                while (d <=9 && b.assign(i, j, d) == false){
                        d++;


                      // if no digit matches, here is the problem, how to 
                      // get back to the previous field and try another digit?
                      // and return null if there's no pervious field 
                if(d == 10){
                      ...
                    return NULL;
                }
            }
        }
    }
    return copyBoard;
 }

Another problem is where to use the recursive call? Any tips? thx!

Complete instruction can been found here: http://www.kth.se/polopoly_fs/1.136980!/Menu/general/column-content/attachment/2-2.pdf

Code: http://www.kth.se/polopoly_fs/1.136981!/Menu/general/column-content/attachment/2-2.zip

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

記憶穿過時間隧道 2024-12-26 13:56:51

您的代码中没有递归。您不能只访问每个字段一次并尝试为其分配值。问题是,您可能能够将 5 分配给字段 (3,4),但可能只有当您到达字段 (6,4) 时,才会发现 (3 ,4)。最终您需要退出递归,直到回到 (3,4) 并在那里尝试另一个值。

通过递归,您可能不会使用嵌套的 for 循环来访问字段,而是通过递归调用访问下一个字段。您要么设法到达最后一个字段,要么尝试所有可能性,然后离开该功能返回到您访问的上一个字段。


旁注:绝对不要为此任务分配动态内存:

//Board *copyBoard = new Board(*this);
Board copyBoard(*this); //if you need a copy in the first place

There is no recursion in your code. You can't just visit each field once and try to assign a value to it. The problem is that you may be able to assign, say, 5 to field (3,4) and it may only be when you get to field (6,4) that it turns out there can't be a 5 at (3, 4). Eventually you need to back out of recursion until you come back to (3,4) and try another value there.

With recursion you might not use nested for loops to visit fields, but visit the next field with a recursive call. Either you manage to reach the last field, or you try all possibilities and then leave the function to get back to the previous field you visited.


Sidenote: definitely don't allocate dynamic memory for this task:

//Board *copyBoard = new Board(*this);
Board copyBoard(*this); //if you need a copy in the first place
相思故 2024-12-26 13:56:51

基本上你可以尝试的是这样的(伪代码)

bool searchSolution(Board board)
{
 Square sq = getEmptySquare(board)
 if(sq == null)
    return true; // no more empty squares means we solved the puzzle

 // otherwise brute force by trying all valid numbers
 foreach (valid nr for sq)
 {
    board.doMove(nr)

    // recurse
    if(searchSolution(board))
        return true

    board.undoMove(nr) // backtrack if no solution found
 }

 // if we reach this point, no valid solution was found and the puzzle is unsolvable
 return false;

}

getEmptySquare(...) 函数可以返回一个随机的空方块或剩余选项数最少的方块。
使用后者将使算法收敛得更快。

Basically what you can try is something like this (pseudocode'ish)

bool searchSolution(Board board)
{
 Square sq = getEmptySquare(board)
 if(sq == null)
    return true; // no more empty squares means we solved the puzzle

 // otherwise brute force by trying all valid numbers
 foreach (valid nr for sq)
 {
    board.doMove(nr)

    // recurse
    if(searchSolution(board))
        return true

    board.undoMove(nr) // backtrack if no solution found
 }

 // if we reach this point, no valid solution was found and the puzzle is unsolvable
 return false;

}

The getEmptySquare(...) function could return a random empty square or the square with the least number of options left.
Using the latter will make the algorithm converge much faster.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文