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

时间:2012-07-14 09:16:52

标签: c algorithm

我正在解决N皇后问题,我们需要在一个4×4国际象棋棋盘上放置4个皇后,这样就不会有两个皇后可以相互攻击。我之前尝试过这个,但我的方法并没有涉及回溯,所以我再次尝试。代码片段是

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);
    }
}

如果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;
}

我从main调用上面的方法

placeQueen(0,0);

我的程序编译成功,但它打印全部为零。


我的递归有问题吗?当我试图学习如何实现回溯算法时,请帮我纠正我的代码!


此外,我无法确定结束递归的基本条件。我如何在这里选择它?

2 个答案:

答案 0 :(得分:1)

您发布的代码中没有打印。如果你在回溯后进行打印,你将回到棋盘上没有皇后的初始状态。放置N个皇后后打印,这也是递归的最终条件。如果您只想打印一个解决方案,请在打印后退出,或者设置一个标志,告诉调用者您已完成,以便完全弹出。如果您打印所有解决方案,那将包括反射和旋转。您可以通过仅在第一级中放置大小/ 2的女王来消除一个反射轴。

此外,您的代码中存在一些明显的逻辑错误,例如

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

只有在没有攻击 文件的情况下,才能放置女王。它不会沿着对角线受到攻击。使用调试器或将printfs添加到代码中以跟踪它试图放置皇后的位置 - 这将帮助您弄清楚它做错了什么。

除了错误之外,你的isAvailable效率非常低。你想知道[i,j]方是沿着文件还是对角线被攻击。为此,您应该在前一个皇后for (m = 0; m < i; m++)的行上有一个循环,但是您只需要三个测试而不是循环来检查文件和对角线。一旦你在文件或对角线上找到任何前任女王,你就完成了,并且方块不可用 - 返回false。 (并且忽略那些告诉你一个函数应该只有一个回报的人 - 他们错了,这里有很长时间的讨论,甚至在代码中对错误率的科学研究也证明了这一点。)只有在没有以前的女王是发现是可用的广场。

你的placeQueen也错了。对于行中每个可用的正方形,您需要放置一个女王然后递归,但您只是找到第一个可用的正方形。只需移除你放置的女王然后返回就可以实现回溯......之前的placeQueen会尝试下一个可用的地点。

再次,跟踪代码以查看它正在做什么。而且,更重要的是,要考虑所需要的逻辑。用文字写出你的算法,说服自己解决问题,然后编写代码来执行算法。

答案 1 :(得分:1)

#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;
}