【问题标题】:Sudoku Recursion, accepting zeros as legal数独递归,接受零为合法
【发布时间】:2013-10-29 04:28:28
【问题描述】:

我正在构建一个递归数独求解器,但遇到了问题。看来我的合法性功能在最终答案中接受 0。但是,它不分配零,零用作占位符来标记未填充的值。当我运行程序时,我得到这样的输出......

**************************************************
 7  4  3 | 8  2  1 | 0  0  0 
 0  6  8 | 0  9  0 | 0  1  0 
 0  0  0 | 0  0  6 | 0  0  4 
---------|---------|---------
 0  0  0 | 0  0  0 | 2  3  9 
 0  0  0 | 0  0  0 | 0  0  0 
 4  1  5 | 0  0  0 | 0  0  0 
---------|---------|---------
 9  0  0 | 5  0  0 | 0  0  0 
 0  2  0 | 0  1  0 | 7  4  0 
 0  0  0 | 2  0  0 | 9  0  5 
**************************************************
**************************************************
 7  4  3 | 8  2  1 | 5  0  0 
 0  6  8 | 0  9  0 | 0  1  0 
 0  0  0 | 0  0  6 | 0  0  4 
---------|---------|---------
 0  0  0 | 0  0  0 | 2  3  9 
 0  0  0 | 0  0  0 | 0  0  0 
 4  1  5 | 0  0  0 | 0  0  0 
---------|---------|---------
 9  0  0 | 5  0  0 | 0  0  0 
 0  2  0 | 0  1  0 | 7  4  0 
 0  0  0 | 2  0  0 | 9  0  5 
**************************************************
**************************************************
 7  4  3 | 8  2  1 | 5  6  0 
 0  6  8 | 0  9  0 | 0  1  0 
 0  0  0 | 0  0  6 | 0  0  4 
---------|---------|---------
 0  0  0 | 0  0  0 | 2  3  9 
 0  0  0 | 0  0  0 | 0  0  0 
 4  1  5 | 0  0  0 | 0  0  0 
---------|---------|---------
 9  0  0 | 5  0  0 | 0  0  0 
 0  2  0 | 0  1  0 | 7  4  0 
 0  0  0 | 2  0  0 | 9  0  5 
**************************************************
**************************************************
 7  4  3 | 8  2  1 | 5  6  0 
 2  6  8 | 0  9  0 | 0  1  0 
 0  0  0 | 0  0  6 | 0  0  4 
---------|---------|---------
 0  0  0 | 0  0  0 | 2  3  9 
 0  0  0 | 0  0  0 | 0  0  0 
 4  1  5 | 0  0  0 | 0  0  0 
---------|---------|---------
 9  0  0 | 5  0  0 | 0  0  0 
 0  2  0 | 0  1  0 | 7  4  0 
 0  0  0 | 2  0  0 | 9  0  5 
**************************************************

正如您在解决拼图时的这些打印输出中所看到的那样,它接受零作为第一列中的最后一个数字。我在我的代码中找不到允许这种情况发生的任何地方。另外,我注意到当我编译时,有时我会认为我会遇到我应该在的内存,但它允许我去。我觉得我的功能有时会让事情变得无中生有。

这是我的合法性功能:

bool Board::isRowLegal(int row){
    bool present[9] = {};
    for(int i = 1; i < theBoard.size(); ++i){
        if(theBoard[row][i] != 0){
            if(present[(theBoard[row][i]) - 1]){
                return false;
            }
            present[(theBoard[row][i]) - 1] = true;
        }
    }
    return true;
}

bool Board::isColumnLegal(int column){
    bool present[9] = {};
    for(int i = 1; i < theBoard.size(); ++i){
        if(theBoard[i][column] != 0){
            if(present[(theBoard[i][column]) - 1]){
                return false;
            }
            present[(theBoard[i][column]) - 1] = true;
        }
    }
    return true;
}

bool Board::isPanelLegal(int rowStart, int colStart){
    // Store the numbers in the panel in one vector.
    vector<int> currentPanel;
    for(int i = rowStart; i < rowStart + THREE; ++i){
        cout << endl;
        for(int j = colStart; j < colStart + THREE; ++j){
            cout << theBoard[i][j];
            currentPanel.push_back(theBoard[i][j]);
        }  
    }

    bool present[9] = {};
    cout << endl << currentPanel.size() << endl;
    for(int k = 0; k < currentPanel.size(); ++k){
        if(currentPanel[k] != 0){
            if(present[currentPanel[k] - 1]){
                return false;
            }
            present[currentPanel[k] - 1] = true;
        }
    }
    return true;
}

我知道它与下标混淆,但作为一般规则,我从下标 1 开始以查找数字。所以第一行第一列的 7 是坐标 1, 1。不是 0, 0。

我相信这是一个必然的问题,也许我没有在一个实例中检查所有数字,但是我年轻的编程眼睛没有看到它。

也有人可以解释为什么我必须在 isPanelLegal 中放入 present[currentPanel[k] - 1]。我可以在其他人中看到为什么,因为向量从 1 开始,但在 isPanelLegal 中,向量从零开始,因为我刚刚在函数的第一部分创建了它。它与 -1 一起工作,没有它就无法工作。

递归部分...

    if(board.isBoardFull()){
        cout << "here" << endl;
        board.display(outStream);
        return true;
    }
    for(int i = ONE; i <= NINE; ++i){
        for(int j = ONE; j <= NINE; ++j){
            //cout << "original" << board.getSquare(i, j) << "coord: " << i << ", " << j << endl;
            if(board.getSquare(i, j) == ZERO){
                //cout << "original: " << board.getSquare(i, j) << "coord: " << i << ", " << j << endl;
                for(int k = ONE; k <= NINE; ++k){
                    board.setSquare(i, j, k);
                    if(board.isLegal(1, 10, 1, 10)){
                        board.display(outStream);
                        addSquare(depth, outStream);
                                            return true;
                    }
                    board.unsetSquare(i, j);
                }
            }

        }
    }
    board.display(outStream);
    return false;
}

谢谢。

【问题讨论】:

  • 为什么一般规则是从下标 1 开始?只是它在您的脑海中更有意义还是在您的代码中有实际原因?我不完全遵循。如果它是合理的,也许可以尝试另一种方式,否则它会在你的编程生涯后期咬你一口,无论是在团队项目中还是在工作中。
  • 我知道,但我从一个开始,以便更好地可视化网格。你看到 0 和 1 的东西有什么不一致的地方吗,也许这就是问题所在?
  • 我意识到这是一个坏习惯,我不做正常的编程,只是在可视化像这样的表格或网格时。
  • 在深入研究输出网格之前,您总是可以输出一个空格。您未用于第一列的内存中的额外空间可能会令人困惑,您需要格外小心。最好只使用 0 索引数组。我将查看您的代码,看看它是否因此而有任何不一致之处,但无论哪种方式,只保留未初始化数组的第一个值/使用只占用内存的垃圾数据通常不是一个好主意。
  • 您需要从 1 循环到数组大小 + 1 :for (i = 1; i &lt; size()+1; ++i) 或将不等式 - &lt; 更改为 &lt;=。否则你总是会丢失数组的最后一个元素。

标签: c++ for-loop recursion vector bounds


【解决方案1】:

我认为您的问题在这里:

bool Board::isRowLegal(int row){
    bool present[9] = {};
    for(int i = 1; i < theBoard.size(); ++i){
        if(theBoard[row][i] != 0){ // This line
            if(present[(theBoard[row][i]) - 1]){
                return false;
            }
            present[(theBoard[row][i]) - 1] = true;
        }
    }
    return true;
}

在你的 for 循环中,如果每个数字都是 0,则函数将返回 true。如果找到 0,您需要做的是返回 false(假设 0 永远不合法,我认为数独就是这种情况)。

bool Board::isRowLegal(int row){
    bool present[9] = {};
    for(int i = 1; i < theBoard.size(); ++i){
        if(theBoard[row][i] == 0)
            return false;

        if(present[(theBoard[row][i]) - 1])
            return false;

        present[(theBoard[row][i]) - 1] = true;
        }
    }
    return true;
}

列也是如此。

编辑:哦,我刚刚意识到您可能还需要在 for 循环中执行 i

【讨论】:

  • 这是有道理的。我会在早上的第一件事尝试。在东海岸迟到了。感谢您的帮助。
  • @TrevorHutto 是 0 用于表示未填充的值吗?如果是这样,并且如果isRowLegal 是检查增量当前合法状态(没有重复出现的值 are 除非它是 unoccupied-sentinal),那么这是错误的。一个合法的“状态”必须满足行、列、面板中没有被占用的单元格值重复,并且那里的关键字occupied
  • @WhozCraig 是的。我不确定零应该代表什么。不管怎样,如果该行包含一个 0 它不应该是一个合法的行,所以它应该返回 false。我不确定这是否是最后一个问题,但它会阻止带有 0 的行声称是合法的。
  • 我们可以不同意合法的行状态,因为它最终是由调用者目的驱动的。如果一行被部分占用,它仍然是合法的,只要该行中没有任何占用的值重复。参与式列验证打开了另一个问题,但具有讽刺意味的是,它们中的两个结合消除了面板级别的检查(必须围绕它来查看它=)。如果这个函数的名称是isLegalCompleteRow 我完全同意你的评估,顺便说一句。
  • 是的,@WhozCraig 是对的,零用于表示未填充的值,我应该改写我的问题以包含它。所以问题是它没有填充一些零,而另一些它正在填充。我在我的代码中找不到可能发生这种情况的位置。
猜你喜欢
  • 1970-01-01
  • 2014-11-02
  • 1970-01-01
  • 1970-01-01
  • 2019-05-22
  • 1970-01-01
  • 2023-03-02
  • 1970-01-01
  • 2013-08-04
相关资源
最近更新 更多