【问题标题】:Backtracking problem similar to Knight-Tour-Problem类似于 Knight-Tour-Problem 的回溯问题
【发布时间】:2021-07-16 05:57:03
【问题描述】:

我正在尝试解决与 Knight-Tour-Problem 类似的问题。问题:

一个马被放置在棋盘的左上角。给你一个数字向量(数字代表棋盘的方格,从左到右编号,从 1 到 64)。骑士必须一个接一个地到达向量中的那些方格,最后你应该输出骑士所走的路径。请注意,骑士可能会多次访问一个广场。

我尝试使用回溯来解决类似于 Knight-Tour 问题的问题。然而,我被困在“不止一次地参观一个广场”上。如果我不设置任何条件,骑士只会在 2 个方格之间来回跳跃,永远不会到达任何地方。我还尝试以某种方式限制骑士返回之前的方格,但后来我得到了一个更大的循环。 在这种特殊情况下,我是否遗漏了什么或回溯通常是错误的?

下面是我的代码。请注意,我只使用了右下角的方块作为骑士到达它的目标,作为一个简单的测试,即便如此,程序还是失败了,调试器显示骑士仍在无限循环中行走。

#include <iostream>
#include <cmath>
using namespace std;

const int n = 8;
bool found = 0;
int *path = new int[n*n];
int pathindex=0;
bool visited[n][n];

void print(int (*matrica)[n]); //function to print a matrix
void printpath(int path[n*n]){
    for(int i=0;i<pathindex;i++)
        cout<<path[i]<<" ";
        cout<<endl;
}

void knight(int (*matrica)[n], int x, int y, int path[n*n], int &pathindex){

if(found){
 return;
}
    if (x==7 && y == 7){ //if knight landed on the target, output the result
       found = 1;
       path[pathindex]=matrica[7][7];
       pathindex++;
       printpath(path);
       return;
      } 
     if(x > n-1 || y > n-1 || x < 0 || y < 0){ //if coordinates out of bounds, dismiss
        return;
    }
    path[pathindex]= matrica[x][y];
    pathindex++;
                                        //all possible knight moves     
        if(path[pathindex-1]!=matrica[x-1][y+2])   //conditions to test if the next square was the one we came from
        knight(matrica, x-1, y+2, path, pathindex);
        
        if(path[pathindex-1]!=matrica[x-2][y+1])
        knight(matrica, x-2, y+1, path, pathindex);
        
        if(path[pathindex-1]!=matrica[x+1][y+2])
        knight(matrica, x+1, y+2, path, pathindex);
        
        if(path[pathindex-1]!=matrica[x+2][y+1])
        knight(matrica, x+2, y+1, path, pathindex);
        
        if(path[pathindex-1]!=matrica[x+2][y-1])
        knight(matrica, x+2, y-1, path, pathindex);
        
        if(path[pathindex-1]!=matrica[x+1][y-2])
        knight(matrica, x+1, y-2, path, pathindex);
        
        if(path[pathindex-1]!=matrica[x-1][y-2])
        knight(matrica, x-1, y-2, path, pathindex);
        
        if(path[pathindex-1]!=matrica[x-2][y-1])
        knight(matrica, x-2, y-1, path, pathindex);
    pathindex--;    
}


int main(){

int matrica[n][n];
int k = 1;
  for(int i=0;i<n;i++){  //number the chess board
    for(int j=0;j<n;j++){
        matrica[i][j] = k;
        k++;}
}
    print(matrica); 
    knight(matrica, 0, 0, path, pathindex);
    if(!found)
    cout<<"No Solution!";
    return 0;
}
void print(int (*matrica)[n]){
    for(int i=0;i<n;i++){
        for(int j=0;j<n;j++){
            if(matrica[i][j]<10)
            cout<<" "<<matrica[i][j]<<" ";
            else
            cout<<matrica[i][j]<<" ";
        }
        cout<<endl;
    }
    cout<<endl<<endl;
}

我怎样才能实现骑士可以多次使用同一个方块,但它不能在原来的循环上行走?

请注意,这不是任何与家庭作业或学校相关的项目,这只是为了我个人的乐趣。

【问题讨论】:

    标签: c++ backtracking chess knights-tour


    【解决方案1】:

    如果按顺序访问方块,这很容易;弄清楚如何从a到b。基本寻路。然后连接。

    如果正方形的数量很少,只需对每个排列执行上述操作。所有对的 a 到 b 的排序成本(b 到 a 相同)。然后解决旅行商寻找最短路线。

    假设第一个,或者如果你不关心最短,这是“从 a 到 b 的路径查找”。这样做时你可以假设它永远不会循环,因为那样不做循环也会起作用。

    简单的解决方案就是画画。有一个充满 -1 的 8x8 网格。写 0。然后在所有骑士从 0 开始的 -1 移动上写 1。然后在所有骑士从 1 开始的 -1 移动上写 2。重复。

    如果你想变得很花哨,你可以用位操作来代替。有 8 个 8 位值。在骑士开始的地方画一个 1 位。一系列的转变和面具可以盲目地翻译“骑士可以到达”面具。存储每组移动的可达掩码,直到到达目标方格。

    现在回溯 - 从目标方格移动到之前快照中的任何合法移动。然后重复直到你得到原来的骑士广场。

    newrow[i]=row[i-2]<<1 | row[i-2]>>1 | row[i+2]<<1 | row[i+2]>>1 | row[i-1]<<2 | row[i-1]>>2 | row[i+1]<<2 | row[i+1]>>2;
    

    进行边界检查,因此row[out of bounds] 为 0 且上限为 8 位,并为每 8 行循环,并且您可以向前或向后执行可到达的骑士掩码 1 步。

    【讨论】:

    • 感谢您的回答!我终于意识到,如果骑士从 A 到 B,那么骑士不会重新访问同一个广场两次(如果他这样做了,那么路线将是不可能的),所以我最终做了简单的 BFS 和每个之间的最短路径两对。最后,我输出了拼接的路径!
    猜你喜欢
    • 1970-01-01
    • 2021-09-07
    • 2016-08-03
    • 2022-08-21
    • 2020-12-20
    • 1970-01-01
    • 1970-01-01
    • 2015-06-21
    相关资源
    最近更新 更多