回溯之N皇后问题

回溯算法思想:为了求得问题的解,先选择某一种可能情况进行试探,在试探过程中,一旦发现原来的选择的假设情况是错误的,就退回一部重新选择,继续向前试探,如此反复进行,直至得到解或证明无解。


如何能够在N X N的国际象棋棋盘上放置N个皇后,使得任何一个皇后都无法直接吃掉其他的皇后?

为了达到此目的,任意两个皇后都不能处于同一横行、纵行或斜线上

思路如下:

1、放置位置检查place放置的皇后不允许处于同一横行、纵行或斜线上

2、显然不同列成立!因为前k-1个皇后分别放在第1到k-1列上,而该皇后放在第k列上;

3、对于第j(1 <=j <=k-1)个皇后,其位置为(q[j],j),要求与(i,k)位置上的皇后不同行的条件为i != q[j];

4、如果设全棋盘的方格作为二维数组A[1...n, 1...n]的下标那样标记,可以看到,对于在同一条对角线上的由左上方到右下方的每个元素有相同的"行-列"值

     同样,在同一条对角线上的由右上方到左下方的每个元素则有相同的"行+列"的值。这样,假设有两个皇后放置在(i, k)和(q[j], j)的位置上。

 那么根据上述原理,仅当:i-k = q[j] - j或者i+k = q[j]+j时,他们才在同一对角线上。

#include <cstdio>
#include <cstdlib>

#define N 15

int n;        //皇后个数
int sum = 0;//可行解个数
int x[N];     //皇后放置的列数

int place(int k)
{
    int i;
    for(i = 1; i < k; i++)
    {
        if(abs(k-i) == abs(x[k] - x[i]) || x[k] == x[i])
        {
            return 0;
        }
    }
    return 1;
}

int queen(int t)
{
    //当放置的皇后超过n时,可行解个数加1,此时n必须大于0
    if(t > n && n > 0)
    {
        sum++;
    }
    else
    {
        for(int i = 1; i <= n; i++)
        {
            //标明第t个皇后放在第i列
            x[t] = i;
            
            //如果可以放在某一位置,则继续放下一皇后
            if(place(t))
            {
                queen(t+1);
            }
        }
    }
    return sum;
}

int main()
{
    int t;
    scanf("%d", &n);
    t = queen(1);
    
    //如果n=0,则可行解个数为0,这种情况一定不要忽略
    if(n == 0) t = 0;
    printf("%d", t);
    return 0;
}

猜你喜欢

转载自blog.csdn.net/weixin_39459624/article/details/79225316