简体   繁体   English

在回溯递归算法中确定基本条件

[英]Deciding the base condition in backtracking recursive algorithm

I was solving the N Queen problem where we need to place 4 queens on a 4 X 4 chess board such that no two queens can attack each other. 我正在解决N皇后问题,我们需要在4×4国际象棋棋盘上放置4个皇后,这样就不会有两个皇后可以相互攻击。 I tried this earlier but my approach did not involve backtracking, so I was trying again. 我之前尝试过这个,但我的方法并没有涉及回溯,所以我再次尝试。 The code snippets are 代码片段是

int size=4,i,j;
int arr[4][4];
int lastjindex[4]; // to store the last location which we may need to backtrack



void placeQueen(int i,int j)
{
    int availableornot=0;

    for(j=0;j<size;j++)
    {
        if(isAvailable(i,j)==1)
        {
            availableornot=1;
            break;
        }
    }

    if(availableornot==1)
    {
        arr[i][j]=1;
        lastjindex[i]=j;

        if((i+1)!=size)
        {
            placeQueen(i+1,0);
        }
    }

    else
    {
        // no column was availabe so we backtrack
        arr[i-1][lastjindex[i-1]]=0;
        placeQueen(i-1,lastjindex[i-1]+1);
    }
}

The isAvailable() method returns 1 if arr[i][j] is not under attack, else it returns 0. 如果arr [i] [j]没有受到攻击,则isAvailable()方法返回1,否则返回0。

int isAvailable(int i,int j)
{
    int m,n,flag=0;

    for(m=0;m<i;m++)
    {
        for(n=0;n<size;n++)
        {
            int k=abs(i-m);
            int l=abs(j-n);

            if(arr[m][j]==0 || arr[k][l]==0)
            {
                flag=1;
                break;
                // means that spot is available
            }
        }
    }
    return flag;
}

I call the above method from main as 我从main调用上面的方法

placeQueen(0,0);

My program compiles successfully but it prints all zeroes. 我的程序编译成功但它打印全部为零。


Is there any problem with my recursion? 我的递归有问题吗? Please help me correct my code as I am trying to learn how to implement backtracking algorithms! 当我试图学习如何实现回溯算法时,请帮我纠正我的代码!


Also I am not able to decide the base condition to end recursion. 此外,我无法决定结束递归的基本条件。 How do I choose it here? 我如何在这里选择它?

There's no printing in the code you posted. 您发布的代码中没有打印。 If you print after you have backtracked, you will be back to the initial condition of no queens on the board. 如果你在回溯后进行打印,你将回到棋盘上没有皇后的初始状态。 Print after you have placed N queens, which is also the end condition for recursion. 放置N个皇后后打印,这也是递归的最终条件。 If you only want to print one solution, exit after printing, or set a flag that tells the caller that you're done so you pop all the way out. 如果您只想打印一个解决方案,请在打印后退出,或者设置一个标志,告诉调用者您已完成,以便完全弹出。 If you print all solutions, that will include reflections and rotations. 如果您打印所有解决方案,那将包括反射和旋转。 You can eliminate one axis of reflection by only placing queens within size/2 in the first level. 您可以通过仅在第一级中放置大小/ 2的女王来消除一个反射轴。

Also, there are some clear logic errors in you code, such as 此外,您的代码中存在一些明显的逻辑错误,例如

arr[m][j]==0 || arr[k][l]==0

A queen can only be placed if it isn't attacked on the file and it isn't attacked along a diagonal. 只有在没有攻击文件并且不会沿着对角线攻击时,才能放置女王。 Use a debugger or add printfs to your code to trace where it is trying to place queens -- that will help you figure out what it is doing wrong. 使用调试器或将printfs添加到代码中以跟踪它试图放置皇后的位置 - 这将帮助您弄清楚它做错了什么。

And aside from being wrong, your isAvailable is very inefficient. 除了错误之外,你的isAvailable非常低效。 You want to know if the [i,j] square is attacked along the file or a diagonal. 你想知道[i,j]方是沿着文件还是对角线被攻击。 For that you should have a single loop over the rows of the previous queens for (m = 0; m < i; m++) , but you only need three tests, not a loop, to check the file and the diagonals. 为此,您应该在前一个皇后的行上有一个循环for (m = 0; m < i; m++) ,但是您只需要三个测试而不是循环来检查文件和对角线。 As soon as you find any previous queen on a file or diagonal, you're done, and the square isn't available -- return false. 一旦你在文件或对角线上找到任何前任女王,你就完成了,并且方块不可用 - 返回false。 (And ignore people who tell you that a function should only have one return -- they are wrong, and there are lengthly discussions here at SO and even scientific studies of error rates in code that bear this out.) Only if no previous queen is found is the square available. (并且忽略那些告诉你一个函数应该只有一个回报的人 - 他们错了,这里有很长时间的讨论,甚至在代码中对错误率的科学研究也证明了这一点。)只有在没有以前的女王是发现是广场可用。

Your placeQueen is also wrong. 你的placeQueen也错了。 For each available square on a row, you need to place a queen and then recurse, but you're just finding the first available square. 对于一行中的每个可用方块,您需要放置一个女王然后递归,但您只是找到第一个可用的方块。 And backtracking is achieved simply by removing the queen you placed and then returning ... the previous level of placeQueen will try the next available spot. 简单地通过移除你放置的女王然后返回来实现回溯......之前的placeQueen将尝试下一个可用的地点。

Again, trace the code to see what it's doing. 再次,跟踪代码以查看它正在做什么。 And, even more importantly, think through the logic of what is needed. 而且,更重要的是,要考虑所需要的逻辑。 Write your algorithm in words, convince yourself that it will solve the problem, then write the code to carry out the algorithm. 用文字写出你的算法,说服自己它会解决问题,然后编写代码来执行算法。

#include <stdio.h>

#define SIZE 4
int size=SIZE;
int arr[SIZE][SIZE] = { 0 };

void placeQueen(int col){
    int r,c;
    if(col == size){//all queen put!
        //print out
        for(r = 0;r<size;++r){
            for(c = 0;c<size;++c)
                printf("%d", arr[c][r]);
            printf("\n");
        }
        printf("\n");
        return ;
    }
    for(r=0;r<size;++r){
        if(isAvailable(col, r)==1){
            arr[col][r]=1;
            placeQueen(col+1);
            arr[col][r]=0;//reset
        }
    }
}

int isAvailable(int col,int row){
    int c;

    for(c=0;c<col;++c){
        int d = col - c;
        if(arr[c][row]==1)
            return 0;//queen already same row
        if(row+d < size && arr[c][row+d]==1 || row-d >= 0 && arr[c][row-d]==1)
            return 0;//queen already same slanting position
    }
    return 1;
}

int main(){
    placeQueen(0);
    return 0;
} 

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

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