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