简体   繁体   English

8回溯拼图

[英]8 Puzzle with Backtracking

I was reading this book from Skiena, Programming Challenges and after the backtracking chapter there was a question about solving the 15-puzzle with backtracking, which I reduce it to 8-puzzle just experimenting. 我正在从Skiena,编程挑战中读到这本书,在回溯章节之后,有一个关于用回溯来解决15-puzzle的问题,我将它简化为8-puzzle进行实验。 I have this recursive code and I am wondering whether it have a chance to find the solution ever. 我有这个递归代码,我想知道它是否有机会找到解决方案。 The code is kind of ugly (be warned): 代码有点难看(被警告):

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int arr[20][20]={
    {3,1,2},
    {4,0,5},
    {6,8,7}
};

int moveX[20]={1,1,1,0,0,-1,-1,-1};
int moveY[20]={0,1,-1,1,-1,0,1,-1};
int depth=0;

int findRow(){
    int i,j;
    for(i=0;i<4;i++){
        for(j=0;j<4;j++){
            if(arr[i][j]==0){
                return i;
            }
        }
    }
}

int findCol(){
    int i,j;
    for(i=0;i<3;i++){
        for(j=0;j<3;j++){
            if(arr[i][j]==0){
                return j;
            }
        }
    }
}

void print(){
    int i,j;
    for(i=0;i<3;i++){
        for(j=0;j<3;j++){
            printf("%i ",arr[i][j]);
        }
        printf("\n");
    }
    printf("\n");
}

int isReady(){
    if(arr[0]==1 && arr[1]==2 && arr[2]==3 && arr[3]==4 && arr[4]==5 && arr[5]==6 && arr[6]==7 && arr[7]==8){
        return 1;
    }
    else return 0;
}

void perm(int row,int col,int n){
    if(n>=9){
        print();
        if(isReady())
            printf("Finished");
        depth++;

        return;
    }

    int i=0;int diffX,diffY,temp;
    int r=findRow();
    int c=findCol();
    temp=arr[r][c];
    arr[r][c]=arr[row][col];
    arr[row][col]=temp;
    for(i=0;i<8;i++){
        diffX=row+moveX[i];
        diffY=col+moveY[i];
        if(diffX>=0 && diffX<4 && diffY>=0 && diffY<4){
            perm(diffX,diffY,n+1);
        }
    }
    temp=arr[r][c];
    arr[r][c]=arr[row][col];
    arr[row][col]=temp;
}

int main()
{
    perm(0,0,0);
    return 0;
}

My question is, is there a chance with this code to find the solution and second, can anybody how the puzzle can be solved in reasonable time? 我的问题是,这个代码是否有机会找到解决方案,其次,任何人都可以在合理的时间内解决这个难题吗?

You have five problems. 你有五个问题。 First, the isReady function is incorrect. 首先, isReady函数不正确。 It should look like this: 它应该如下所示:

int isReady(){
    if(arr[0][0]==1 && arr[0][1]==2 && arr[0][2]==3 &&
            arr[1][0]==4 && arr[1][1]==5 && arr[1][2]==6 &&
            arr[2][0]==7 && arr[2][1]==8){
        return 1;
    }
    else return 0;
}

Second, you are exceeding your puzzle bounds with diffX and diffY . 其次,你使用diffXdiffY超越你的拼图界限。 You need to change this: 你需要改变这个:

    if(diffX>=0 && diffX<4 && diffY>=0 && diffY<4){

to this: 对此:

    if(diffX>=0 && diffX<3 && diffY>=0 && diffY<3){

Third, your findRow function also exceeds the puzzle bounds. 第三,你的findRow函数也超出了拼图界限。 Change all of the 4 to 3 . 将所有4改为3

Fourth, you should check your victory condition only after you have made your move. 第四,只有在你移动后才能检查你的胜利状态。 So move your victory check below the swap: 所以在交换下面移动你的胜利检查:

temp=arr[r][c];
arr[r][c]=arr[row][col];
arr[row][col]=temp;
// This victory check is now below the move.
if(n>=9){
    print();
    if(isReady())
        printf("Finished");
    depth++;

    return;
}

Fifth, you should change your initial call from this: 第五,你应该改变你的初始电话:

perm(0,0,0);

to this: 对此:

perm(1,1,0);

The way you have it, you are always forcing a move to the upper left as your first move. 你拥有它的方式,你总是强行向左上方移动作为你的第一步。 The modified way keeps the 0 in the center so it doesn't force your first move. 修改后的方式将0保持在中心位置,因此不会强制您第一次移动。 When I ran this code with all of the modifications I made, it found 3 solutions. 当我使用我所做的所有修改运行此代码时,它找到了3个解决方案。 When I further modified the code to check for solutions at any depth, it found 2 solutions at depth 8 and 3 solutions at depth 9. 当我进一步修改代码以检查任何深度的解时,它在深度8找到2个解,在深度9找到3个解。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM