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