每日刷题(五十二)
BASIC-27、2n皇后问题
这个题确实有点难度,但是之前我也出过关于N皇后问题的博文分析——算法一:递归(包含Hanoi问题、N皇后问题、逆波兰表达式、爬楼梯、放苹果、全排列)如果看过这篇博文,就知道解决这个题只是需要多定义一些东西罢了
我们需要定义三个数组,一个二维数组a[10][10],另外两个一维数组b,c用来存放黑皇后和白皇后每一行的列号的。
首先我们定义f1函数用来递归出黑皇后的所有符合条件的位置,每当一种位置布置好后就跳到f2函数递归出白皇后的所有符合条件的位置,f1函数和f2函数其实差别不大,但是f2函数需要考虑到已确定好的黑皇后的位置信息,不能重复。
这个题还有一个很重要的就是回溯,每当递归一个f1(k + 1)或者f2(k + 1)我们就要在后面把数组a和对应一维数组记录位置的值初始化,以防止干扰后续操作。比方说f1(3)的位置都不对,那么就会跳回f1(2),相当于前面那种布置不符合题意,那么就需要把数组a和b最近修改过的元素都回归本源,这样才不会影响新的递归调用。
详细C代码如下:
#include<stdio.h>
int a[10][10];
int n;
int b[10] = {-1, -1, -1, -1, -1, -1, -1, -1, -1, -1}; //记录第i行黑皇后的列号位置
int c[10] = {-1, -1, -1, -1, -1, -1, -1, -1, -1, -1}; //记录第i行白皇后的列号位置
int sum = 0;
void f2(int k) //在0~k-1行皇后摆好的情况下摆第k行及其后的白皇后
{
int i, j;
if(k == n)
sum++;
else
{
for(i = 0; i < n; i++)
{
if(a[k][i] == 0 || a[k][i] == 2)
continue;
for(j = 0; j < k; j++)
{
if(abs(k - j) == abs(i - c[j])) //对角线上
{
break;
}
if(a[j][i] == 3) //在正上方
break;
}
if(j == k)
{
a[k][i] = 3;
c[k] = i;
f2(k + 1);
a[k][i] = 1;
c[k] = -1;
}
}
}
}
void f1(int k) //在0~k-1行皇后摆好的情况下摆第k行及其后的黑皇后
{
int i, j;
if(k == n)
{
f2(0);
}
else
{
for(i = 0; i < n; i++) //n个位置可以选择
{
if(a[k][i] == 0) //如果第k行第i列位置不可放则continue
continue;
j = 0;
for(; j < k; j++)
{
if(abs(k - j) == abs(i - b[j])) //对角线上
break;
if(a[j][i] == 2) //在正上方
break;
}
if(j == k)
{
a[k][i] = 2; //在数组a中记录下黑皇后的位置
b[k] = i; //在数组b中记录下黑皇后的列号
f1(k + 1);
a[k][i] = 1;
b[k] = -1;
}
}
}
}
int main()
{
int i1, j1;
for(i1 = 0; i1 < 10; i1++)
{
for(j1 = 0; j1 < 10; j1++)
{
a[i1][j1] = 1;
}
}
scanf("%d", &n);
int i, j;
for(i = 0; i < n; i++)
for(j = 0; j < n; j++)
scanf("%d", &a[i][j]);
f1(0); //在0~k-1行皇后摆好的情况下摆第k行及其后的皇后
printf("%d\n", sum);
return 0;
}
部分运行结果如下: