骑士的巡回蛮力

时间:2018-03-28 23:44:24

标签: recursion backtracking knights-tour

我迷失了骑士如何使用递归回溯。我已经尝试了多种方法,因为你可以看到它已经注释了一些尝试,但是它如何知道回溯到多远才能再次向前推进?我对递归的理解是每次使用新参数构建堆栈帧时函数调用自身,当它到达基本情况时,它返回到堆栈帧,在这种情况下向后移动。有人能指出我正确的方向吗?感谢。

#include "stdafx.h"
#include <iostream>
#include <iomanip>

using namespace std;


int GAMEBOARD[8][8] = { 0 };
int TOTAL_MOVES = 0, BAD_MOVES = 0;

bool moveKnight(int row, int col, int movNum);
void print();

int main()
{
    int startRow = 3, startCol = 3;
    int moveNum = 1;

    GAMEBOARD[startRow][startCol] = moveNum;
    TOTAL_MOVES++;

    moveKnight(startRow, startCol, moveNum);

    if (moveKnight(startRow, startCol, moveNum) == true) {
        cout << "Knight's Tour Solved! It took " << TOTAL_MOVES <<
            " total moves and " << BAD_MOVES << " bad moves." << endl;
    }

    system("pause");
    return 0;
}

bool moveKnight(int row, int col, int moveNum)
{
    GAMEBOARD[row][col] = moveNum;
    TOTAL_MOVES++;


    if (moveNum == 64) {
        return true;
    }

    if (GAMEBOARD[row][col] != 0) {
        GAMEBOARD[row][col] = 0;
        print();
        system("pause");
        return moveKnight(row, col, moveNum);
    }

// commented out
    /*if (GAMEBOARD[row - 2][col + 1] != 0) {
        print();
        system("pause");
        return moveKnight(row - 2, col + 1, moveNum + 1);
    }
    else if (GAMEBOARD[row - 1][col + 2] != 0) {
        print();
        system("pause");
        return moveKnight(row - 1, col + 2, moveNum + 1);
    }
    else if (GAMEBOARD[row + 1][col + 2] != 0) {
        print();
        system("pause");
        return moveKnight(row + 1, col + 2, moveNum + 1);
    }
    else if (GAMEBOARD[row + 2][col + 1] != 0) {
        print();
        system("pause");
        return moveKnight(row + 2, col + 1, moveNum + 1);
    }
    else if (GAMEBOARD[row + 2][col - 1] != 0) {
        print();
        system("pause");
        return moveKnight(row + 2, col - 1, moveNum + 1);
    }
    else if (GAMEBOARD[row + 1][col - 2] != 0) {
        print();
        system("pause");
        return moveKnight(row + 1, col - 2, moveNum + 1);
    }
    else if (GAMEBOARD[row - 1][col - 2] != 0) {
        print();
        system("pause");
        return moveKnight(row - 1, col - 2, moveNum + 1);
    }
    else if (GAMEBOARD[row - 2][col - 1] != 0) {
        print();
        system("pause");
        return moveKnight(row - 2, col - 1, moveNum + 1);
    }

    return false;*/






    else if (row - 2 >= 0 && row - 2 <= 7 && col + 1 >= 0
        && col + 1 <= 7 && GAMEBOARD[row - 2][col + 1] == 0) {
        GAMEBOARD[row - 2][col + 1] = moveNum;
        print();
        system("pause");
        return moveKnight(row - 2, col + 1, moveNum + 1);
    }
    else if (row - 1 >= 0 && row - 1 <= 7 && col + 2 >= 0
        && col + 2 <= 7 && GAMEBOARD[row - 1][col + 2] == 0) {
        GAMEBOARD[row - 1][col + 2] = moveNum;
        print();
        system("pause");
        return moveKnight(row - 1, col + 2, moveNum + 1);
    }
    else if (row + 1 >= 0 && row + 1 <= 7 && col + 2 >= 0
        && col + 2 <= 7 && GAMEBOARD[row + 1][col + 2] == 0) {
        GAMEBOARD[row + 1][col + 2] = moveNum;
        print();
        system("pause");
        return moveKnight(row + 1, col + 2, moveNum + 1);
    }
    else if (row + 2 >= 0 && row + 2 <= 7 && col + 1 >= 0
        && col + 1 <= 7 && GAMEBOARD[row + 2][col + 1] == 0) {
        GAMEBOARD[row + 2][col + 1] = moveNum;
        print();
        system("pause");
        return moveKnight(row + 2, col + 1, moveNum + 1);
    }
    else if (row + 2 >= 0 && row + 2 <= 7 && col - 1 >= 0
        && col - 1 <= 7 && GAMEBOARD[row + 2][col - 1] == 0) {
        GAMEBOARD[row + 2][col - 1] = moveNum;
        print();
        system("pause");
        return moveKnight(row + 2, col - 1, moveNum + 1);
    }
    else if (row + 1 >= 0 && row + 1 <= 7 && col - 2 >= 0
        && col - 2 <= 7 && GAMEBOARD[row + 1][col - 2] == 0) {
        GAMEBOARD[row + 1][col - 2] = moveNum;
        print();
        system("pause");
        return moveKnight(row + 1, col - 2, moveNum + 1);
    }
    else if (row - 1 >= 0 && row - 1 <= 7 && col - 2 >= 0
        && col - 2 <= 7 && GAMEBOARD[row - 1][col - 2] == 0) {
        GAMEBOARD[row - 1][col - 2] = moveNum;
        print();
        system("pause");
        return moveKnight(row - 1, col - 2, moveNum + 1);
    }
    else if (row - 2 >= 0 && row - 2 <= 7 && col - 1 >= 0
        && col - 1 <= 7 && GAMEBOARD[row - 2][col - 1] == 0) {
        GAMEBOARD[row - 2][col - 1] = moveNum;
        print();
        system("pause");
        return moveKnight(row - 2, col - 1, moveNum + 1);
    }




// commented out
    /*if (row - 2 < 0 || row - 2 > 7 || col + 1 < 0
        || col + 1 > 7 || GAMEBOARD[row - 2][col + 1] != 0) {
        GAMEBOARD[row - 2][col + 1] = 0;
        return moveKnight(row - 2, col + 1, moveNum + 1);
    }
    else if (row - 1 < 0 || row - 1 > 7 || col + 2 < 0
        || col + 2 > 7 || GAMEBOARD[row - 1][col + 2] != 0) {
        GAMEBOARD[row - 1][col + 2] = 0;
        return moveKnight(row - 1, col + 2, moveNum + 1);
    }
    else if (row + 1 < 0 || row + 1 > 7 || col + 2 < 0
        || col + 2 > 7 || GAMEBOARD[row + 1][col + 2] != 0) {
        GAMEBOARD[row + 1][col + 2] = 0;
        moveKnight(row + 1, col + 2, moveNum + 1);
        return false;
    }
    else if (row + 2 < 0 || row + 2 > 7 || col + 1 < 0
        || col + 1 > 7 || GAMEBOARD[row + 2][col + 1] != 0) {
        GAMEBOARD[row + 2][col + 1] = 0;
        moveKnight(row + 2, col + 1, moveNum + 1);
        return false;
    }
    else if (row + 2 < 0 || row + 2 > 7 || col - 1 < 0
        || col - 1 > 7 || GAMEBOARD[row + 2][col - 1] != 0) {
        GAMEBOARD[row + 2][col - 1] = 0;
        moveKnight(row + 2, col - 1, moveNum + 1);
        return false;
    }
    else if (row + 1 < 0 || row + 1 > 7 || col - 2 < 0
        || col - 2 > 7 || GAMEBOARD[row + 1][col - 2] != 0) {
        GAMEBOARD[row + 1][col - 2] = 0;
        moveKnight(row + 1, col - 2, moveNum + 1);
        return false;
    }
    else if (row - 1 < 0 || row - 1 > 7 || col - 2 < 0
        || col - 2 > 7 || GAMEBOARD[row - 1][col - 2] != 0) {
        GAMEBOARD[row - 1][col - 2] = 0;
        moveKnight(row - 1, col - 2, moveNum + 1);
        return false;
    }
    else if (row - 2 < 0 || row - 2 > 7 || col - 1 < 0
        || col - 1 > 7 || GAMEBOARD[row - 2][col - 1] != 0) {
        GAMEBOARD[row - 2][col - 1] = 0;
        moveKnight(row - 2, col - 1, moveNum + 1);
        return false;
    }
        */


    cout << endl << endl;

    return false;
}

void print()
{
    for (int row = 0; row <= 7; row++) {
        for (int col = 0; col <= 7; col++) {
            cout << setw(5) << GAMEBOARD[row][col];
        }
        cout << endl;
    }
}

1 个答案:

答案 0 :(得分:0)

递归可能很棘手! 我强烈建议您在尝试开始编写代码之前仔细考虑算法的工作方式。

首先明确定义基本案例。你做得很好。我们在这里:

if (moveNum == 64) {
    return true;
}

现在,我们需要考虑如何处理来自每个位置的骑士的8种可能动作。我将使用一些sudo代码简化你的代码:

moves = [[2, 1], [2, 1], [-2, -1], etc...]; // 8 moves total
for (move : moves) {
    newRow = row + move[0];
    newCol = col + move[1];

    if (InBounds(newRow, newCol) && GAMEBOARD[newRow][newCol] == 0) {
        // Backtracking logic goes here
    }
}

这段代码基本上和你的if语句做同样的事情,但是更容易使用和概念化。

递归回溯基本上有两个步骤。首先,我们检查是否已达到基本情况。其次,我们处理了重复案件。通过递归回溯,这包括几个步骤:

  1. 做某事(在这种情况下,移动骑士)
  2. 进行递归调用以检查是否会产生解决方案
  3. 如果这导致了解决方案,请告诉调用者此函数我们找到了解决方案。此外,您可能希望对找到的解决方案采取一些措施。
  4. 这不会产生解决方案。撤消我们在第一步中所做的事情,看看其他递归案例是否会导致解决方案
  5. 如果没有导致找到解决方案的递归情况,请告诉调用者当前位置找不到解。
  6. 将此格式应用于骑士之旅:

    1. 在棋盘上移动:GAMEBOARD[newRow][newCol] = moveNum
    2. 测试此移动是否会产生解决方案:result = moveKnight(newRow, newCol, moveNum + 1)
    3. 如果我们找到了解决方案,那么现在就返回true。 if (result) {return true;}
    4. 如果此举不起作用,撤消我们所做的移动:GAMEBOARD[newRow][newCol] = 0。然后,我们应该看看其他递归情况是否会导致解决方案。我的代码通过循环遍历每个移动来处理这个问题。您通过执行一系列if / else语句来处理它。
    5. 此声明没有任何动作导致解决方案。我们应该return false来表明这一点。
    6. 把这一切放在一起,我们得到:

      bool moveKnight(int row, int col, int moveNum) {
      
        if (moveNum == 64) {
            return true;
        }
        moves = [[2, 1], [2, 1], [-2, -1], etc...]; // 8 moves total
        for (move : moves) {
          int newRow = row + move[0];
          int newCol = col + move[1];
      
          if (InBounds(newRow, newCol) && GAMEBOARD[newRow][newCol] == 0) {
            GAMEBOARD[newRow][newCol] = moveNum;
            bool result = moveKnight(newRow, newCol, moveNum + 1);
            if (result) {
              return true;
            } else {
              // Undo this move
              GAMEBOARD[newRow][newCol] = 0;
            }
          }
        }
        return false;
      }
      

      因为我们在找到正确的解决方案时不撤消移动,所以当moveKnight返回true时,GAMEBOARD将包含解决方案。