1. 程式人生 > >回溯之N皇后問題

回溯之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;
}