当前位置: 首页 > 知识库问答 >
问题:

幻方回溯与递归C++

唐法
2023-03-14

我试图用C++中的回溯和递归来解决C++中的幻方问题。特别适用于4x4数组。

4x4幻方解的一个例子如下,其中每行、每列和对角线加34:

我所做的更改是:用户输入一些值,这些值将启动算法。

我的算法是这样的:

在这里你可以更好地欣赏图像。

我有一个概念,算法应该如何工作,以解决幻方的问题,回溯和递归,但我有问题。

其中之一是:

成就并没有让我的算法“忽略”用户已经输入的值。

我在C++中的代码在GitHub的这个链接中。代码如下:

#include <iostream>

using namespace std;

int sudoku[4][4];

int row = 0;
int column = 0;

bool isFull(int s[4][4]){
    for(int i = 0; i < 4; i++){
        for(int j = 0; j < 4; j++){
            if(s[4][4] == 0){
                return false;
            }
        }
    }

    return true;
}

void printMatrix(int s[4][4]){
    for(int i = 0; i < 4; i++){
        for(int j = 0; j < 4; j++){
            cout << sudoku[i][j] << "  ";
        }
        cout << endl;
    }
}

bool isAssigned(int row, int column){
    if(row == 1 && column == 0 ||
       row == 0 && column == 2 ||
       row == 1 && column == 2){
        return true;
    } else return false;
}

bool verify(int s[4][4], int row, int column){

    bool flag = false;

    int sumrow = 0, sumcolumn = 0, sumDiagonal = 0, sumDiagonal2 = 0;
    int value = 3;
    for(int i = 0; i < 4; i++){
        sumrow = sumrow + s[row][i];
        sumcolumn = sumcolumn + s[i][column];
        sumDiagonal = sumDiagonal + s[i][i];
        sumDiagonal2 = sumDiagonal2 + s[i][value];
        value--;
    }

    if(sumrow <= 34 && sumcolumn <= 34 && sumDiagonal2 <= 34 && sumDiagonal2 <= 34){
        return true;
    } else return false;

}

bool backtracking(int s[4][4], int row, int column){

    if(isFull(s) == true){ //verify if there are no zeros in the matrix
        printMatrix(sudoku);
        cout<<"Solution find ";
    }
    else {

        if(isAssigned(row, column) == false){ // verify if the cell is already assigned

            for(int i = 1; i <= 16; i++){

                s[row][column] = i; // assigned value

                if(verify(s, row, column) == true){ // verify that the sum of the column, row and diagonal not greater 34

                    if(column == 4) {
                            row++;
                            column=0;
                    }

                    backtracking(s, row, column + 1); // recursion
                    printMatrix(s); // Print the matrix to see progress
                    cout<<endl;

                } else { // the sum value exceeds 34
                    s[row][column] = 0;
                    return false;
                }
            }
        }
    }
}

int main(){

    sudoku[1][0] = 5;
    sudoku[0][2] = 15;
    sudoku[1][2] = 10;

    backtracking(sudoku, row, column);

    return 0;
}

我的算法主要如下:

显然,本例中有一些特性,但是如果您看到我的代码,您就会意识到我试图做什么。

也许我的解决方法不起作用或不好。

发布这篇文章的原因是,我需要帮助来改进或者需要帮助来解决代码所做的。下面是我运行的主要函数和输出:

bool backtracking(int s[4][4], int row, int column){

    if(isFull(s) == true){ //verify if there are no zeros in the matrix
        printMatrix(sudoku);
        cout<<"Solution find ";
    }
    else {

        if(isAssigned(row, column) == false){ // verify if the cell is already assigned

            for(int i = 1; i <= 16; i++){

                s[row][column] = i; // assigned value

                if(verify(s, row, column) == true){ // verify that the sum of the column, row and diagonal not greater 34

                    if(column == 4) {
                            row++;
                            column=0;
                    }

                    backtracking(s, row, column + 1); // recursion
                    printMatrix(s); // Print the matrix to see progress
                    cout<<endl;

                } else { // the sum value exceeds 34
                    s[row][column] = 0;
                    return false;
                }
            }
        }
    }
}

产出:

3  16  15  0
5  0  10   0
0  0  0    0
0  0  0    0

正如我之前所说的,当我发现一个用户已经被分配的值时,我会遇到问题。这是第一次使用回溯,这就是为什么我觉得有点困难。谢谢你的一切。

共有1个答案

周浩博
2023-03-14

嗯,是的,

最近不得不做一些类似的事情,一些地方来“修复”这个问题

从网格中已经分配的数字的位图(1-16)开始。也就是说,用户输入的那些已经标记为“正在使用”。只为该位图中尚未标记的网格分配数字。如果使用非递归方法,则需要使用堆栈来知道哪些已经测试过,以便在回溯时“取消设置”。如果使用递归方法(只有16个深度递归;))将位图和已放置的正方形作为副本传递,而不是引用;)

 类似资料:
  • 我正在开发高级培养皿网络编辑器/模拟器。首先,这里有一些词汇 圆圈=位置 矩形=过渡 就地整数 = 标记 过渡状态=防护 我被困在通过过渡的守卫。守卫是一个条件,如果你想执行转换,这需要是真的。我知道我应该以某种方式使用回溯,但我不知道在程序开始之前进入过渡的位置数,所以我不能使用循环,因为我不知道我需要多少个循环。 所以,我想从第一位获取第一个令牌,从第二位获取第一令牌,然后尝试通过守卫,如果通

  • 我的任务是用回溯和递归的方法解决一个迷宫。这更多的是一个关于这个概念的概念问题。 回溯电话是如何接通的?从我所看到的所有示例来看,似乎递归总是在回溯步骤之前立即调用,所以回溯是无法实现的。谁能给我解释一下回溯步骤是怎么达到的?

  • 我的问题是,当一个9不能正确添加时,该方法会中断。不知何故,我不知道如何让它回到前一点,并向上数,这将创建一个新的“路径”,所以我想如果我做对了,一切都应该很好。我仍然在使用递归:-/ 正如我所知,我认为Sudokurecrect()做了它应该做的事情。编辑:您可以忽略布尔测试。我知道我不使用它,我试着想一些东西,但显然我不知道如何使用它。 输出为 在那之后,不管检查哪个变体。所以问题是一样的。

  • 我对编码还是很陌生的,我正在尝试一些稍微困难的主题,例如修改数独递归回溯程序的解决方案。最初的解决方案是针对大小为3x3的数独,我希望我的解决方案可以与正常大小的数独(9x9)一起使用。3x3解决方案在这里找到。 我觉得我对算法非常了解:对于网格中的每个列表(包含该单元格的可能值),在每一步尝试每个数字,确保电路板仍然有效,移动到下一个列表,分配一个可能的数字直到其有效,等等。如果当前电路板不正确

  • 我正在创建一个递归导航迷宫的程序。代码: 然而,每当我到达死胡同时,它都不会回溯。当我调试时,它表明当程序从递归或“回溯”返回时,我的起始值专注于停留在我的死胡同空间。 例如: 9是我的出发点。2是我的退出。4是我的道路。1 表示墙壁。当我到达一个死胡同时(在本例中为第 7 行,第 2 列)。我的立场是等于整个程序其余部分的死胡同空间。这是为什么呢?

  • 回溯和递归有什么区别?这个程序是如何运作的?