c ++中的递归回溯骑士之旅

Posted

技术标签:

【中文标题】c ++中的递归回溯骑士之旅【英文标题】:Recursive backtracking knights tour in c ++ 【发布时间】:2013-04-09 00:11:14 【问题描述】:

所以,简而言之,我正在研究一个骑士的巡回演出计划。如果你不知道那是什么,马就会被放在棋盘上,你必须将它移动到棋盘上的每个位置一次。我正在使用递归函数,但无法让我的回溯工作。我可以在 5x5 板上达到 22 步,但程序不会备份并尝试不同的路径。我只发布了我的代码的递归部分(抱歉它有点长)任何见解都会非常有帮助。非常感谢!

`bool findPath ( int board[][boardSize + 4], int &currRow, int &currCol, int &currMove,int boardSize )

    int i, j;
    bool foundSpot;

    board[currRow][currCol] = currMove;

    if ( currMove == boardSize * boardSize )
        return true;

    for ( i = 0; i < boardSize + 4; i++ )
    
        for ( j = 0; j < boardSize + 4; j++ )
            cout << setw (3) << board[i][j];
        cout<<endl;
    
    cout << endl;

    if ( board[currRow - 2][currCol - 1] == 0 )
    
        currMove += 1;
        board[currRow - 2][currCol - 1] = currMove;
        currRow -= 2;
        currCol -= 1;
        if ( findPath( board, currRow, currCol, currMove, boardSize ) )
            return true;
    

    if ( board[currRow - 2][currCol + 1] == 0 )
    
        currMove += 1;
        board[currRow - 2][currCol + 1] = currMove ;
        currRow -= 2;
        currCol += 1;
        if ( findPath( board, currRow, currCol, currMove, boardSize ) )
            return true;
    

    if ( board[currRow - 1][currCol + 2] == 0 )
    
        currMove += 1;
        board[currRow - 1][currCol + 2] = currMove ;
        currRow -= 1;
        currCol += 2;
        if ( findPath( board, currRow, currCol, currMove, boardSize ) )
            return true;
    

    if ( board[currRow + 1][currCol + 2] == 0 )
           
        currMove += 1;
        board[currRow + 1][currCol + 2] = currMove ;
        currRow += 1;
        currCol += 2;
        if ( findPath( board, currRow, currCol, currMove, boardSize ) )
            return true;
    

    if ( board[currRow + 2][currCol + 1] == 0 )
    
        currMove += 1;
        board[currRow + 2][currCol + 1] = currMove ;
        currRow += 2;
        currCol += 1;
        if ( findPath( board, currRow, currCol, currMove, boardSize ) )
            return true;
    

    if ( board[currRow + 2][currCol - 1] == 0 )
    
        currMove += 1;
        board[currRow + 2][currCol - 1] = currMove ;
        currRow += 2;
        currCol -= 1;
        if ( findPath( board, currRow, currCol, currMove, boardSize ) )
            return true;
    

    if ( board[currRow + 1][currCol - 2] == 0 )
           
        currMove += 1;
        board[currRow + 1][currCol - 2] = currMove ;
        currRow += 1;
        currCol -= 2;
        if ( findPath( board, currRow, currCol, currMove, boardSize ) )
            return true;
    

    if ( board[currRow - 1][currCol - 2] == 0 )
           
        currMove += 1;
        board[currRow - 1][currCol - 2] = currMove ;        
        currRow -= 1;
        currCol -= 2;
        if ( findPath( board, currRow, currCol, currMove, boardSize ) )
            return true;
    
    board[currRow][currCol] = 0;
    currMove -= 2;
    return false;
`

【问题讨论】:

欢迎来到 Stack Overflow!要求人们发现代码中的错误并不是特别有效。您应该使用调试器(或添加打印语句)来隔离问题,方法是跟踪程序的进度,并将其与您期望发生的情况进行比较。一旦两者发生分歧,那么您就发现了您的问题。 (然后如果有必要,你应该构造一个minimal test-case。) 我不认为在每个递归块中更改 currRow 和 currCol 是一个好主意 - 这意味着下一个递归块将从错误的方格开始,您的 board[currRow][currCol] = 0; 将清除最后一个递归和不是您在此级别上的步骤(设置在最顶部)。为什么要设置板并更改每个 if 中的行和列变量?递归调用不应该解决这个问题吗?而且我认为您不希望您的行、列、移动输入成为引用 - 而是按值传递! 您还需要对每个if (board[][] == 0) 测试进行范围检查,以确保两个坐标都在范围内。为了避免重复自己,您可能需要构建一个移动排列数组并循环遍历它们。 【参考方案1】:

我用 c++ 编写了以下骑士之旅的实现:

#include<cstdio>
#include<iostream>
#define MAX 10

using namespace std;
int tour=1;
int board[MAX][MAX];

bool is_travelled(int,int);
bool knights_tour(int,int,int,int);
void initialize(int);
void display(int);

int main(int argc,char** argv)
    int n;
    scanf("%d",&n);
    for(int i=0;i<10;i++)
        for(int j=0;j<10;j++)
            board[i][j]=-1;
        
    
    initialize(n);
    display(n);
    return 0;


bool is_travelled(int x,int y)
    if(x<0 || y<0)return true;
    if(board[x][y]==-1)return false;
    return true;


bool knights_tour(int i,int j,int n,int k) // k=number of places remained , n=side of chess_board;
    int x,y;
    if(k==0)return true;
    // hard-coded cases;
    // reordering of the cases have significant effect on the execution time
    x=i+2;y=j+1;
    if((!is_travelled(x,y))&&x<n&&y<n)
        board[x][y]=tour;
        tour+=1;
        if(knights_tour(x,y,n,k-1))return true;
        board[x][y]=-1;
        tour-=1;
    
    x=i+1;y=j+2;
    if((!is_travelled(x,y))&&x<n&&y<n)
        board[x][y]=tour;
        tour+=1;
        if(knights_tour(x,y,n,k-1))return true;
        board[x][y]=-1;
        tour-=1;
    
    x=i-1;y=j+2;
    if((!is_travelled(x,y))&&x<n&&y<n)
        board[x][y]=tour;
        tour+=1;
        if(knights_tour(x,y,n,k-1))return true;
        board[x][y]=-1;
        tour-=1;
    
    x=i-2;y=j+1;
    if((!is_travelled(x,y))&&x<n&&y<n)
        board[x][y]=tour;
        tour+=1;
        if(knights_tour(x,y,n,k-1))return true;
        board[x][y]=-1;
        tour-=1;
    
    x=i-2;y=j-1;
    if((!is_travelled(x,y))&&x<n&&y<n)
        board[x][y]=tour;
        tour+=1;
        if(knights_tour(x,y,n,k-1))return true;
        board[x][y]=-1;
        tour-=1;
    
    x=i-1;y=j-2;
    if((!is_travelled(x,y))&&x<n&&y<n)
        board[x][y]=tour;
        tour+=1;
        if(knights_tour(x,y,n,k-1))return true;
        board[x][y]=-1;
        tour-=1;
    
    x=i+1;y=j-2;
    if((!is_travelled(x,y))&&x+y<n&&x<n&&y<n)
        board[x][y]=tour;
        tour+=1;
        if(knights_tour(x,y,n,k-1))return true;
        board[x][y]=-1;
        tour-=1;
    
    x=i+2;y=j-1;
    if((!is_travelled(x,y))&&x<n&&y<n)
        board[x][y]=tour;
        tour+=1;
        if(knights_tour(x,y,n,k-1))return true;
        board[x][y]=-1;
        tour-=1;
    
    return false;

void initialize(int n)
    for(int i=0;i<n;i++)
        for(int j=0;j<n;j++)
            board[i][j]=0;
            int r=knights_tour(i,j,n,n*n-1);
            if(r==1)return;
            board[i][j]=-1;
        
    


void display(int n)
    for(int i=0;i<n;i++)
        for(int j=0;j<n;j++)
            printf("%2d ",board[i][j]);
        
        printf("\n");
    
    cout<<endl;

希望这会有所帮助。 快乐编码!

【讨论】:

以上是关于c ++中的递归回溯骑士之旅的主要内容,如果未能解决你的问题,请参考以下文章

求子集 递归加回溯

骑士之旅中的堆栈实现[关闭]

在递归期间堆栈框架外观。 C vs汇编

C语言的两个问题: 所有的递归程序均可以用非递归算法实现?递归函数中的形式参数是自动变量吗? c语言中

C语言 编写递归函数

递归与回溯:python列表组合问题