在n×n棋盘上放彼此不受攻击的n个皇后。
按国际象棋规则,皇后可攻击同行、同列、同一斜线的棋子。
等价于在n×n格的棋盘上放置n个皇后,任何2个皇后不放在同一行或同一列或同一斜线上。
可以用一个数组存储每行中的皇后的纵座标,例如n=8时,X=(4,6,8,2,7,1,3,5)表示第一行的皇后的纵座标为4,
第二行的皇后的纵座标为6,……
比较常用的一种求解办法为通过子集树求解,约束条件为abs(k-j)!=abs(x[j]-x[k]) 并且 x[j]!=x[k]。
其实这个问题也可以描述为n个数字的排列问题,约束条件为abs(k-j)!=abs(x[j]-x[k]),这样该问题就可以用全排列的算法求解。
子集树求解的程序为:
#include <cstdio>
#include <cmath>
int x[20];
int n,count;
int Place(int k)
{
int j;
for(j=1;j<k;j++)
if((abs(k-j)==abs(x[j]-x[k]))||(x[j]==x[k]))
return 0;
return 1;
}
void Backtrack(int t)
{
int i;
if(t>n)
{
for(i=1;i<=n;i++)
printf("%d ",x[i]);
printf("\n");
count++;
}
else
for(i=1;i<=n;i++)
{
x[t]=i;
if(Place(t))
Backtrack(t+1);
}
}
int main()
{
printf("请输入n:");
scanf("%d",&n);
Backtrack(1);
printf("共%d组答案\n",count);
return 0;
}
排列树求解的程序为:
#include <cstdio>
#include <cmath>
int n,count;
int Place(int data[], int k)
{
int j;
for(j=1;j<k;j++)
if(abs(k-j)==abs(data[j]-data[k]))
return 0;
return 1;
}
void swap(int &x, int &y)
{
int temp;
temp=x;
x=y;
y=temp;
}
void perm(int data[], int k, int n)
{
int i;
if(k>n)
{
for(i=1;i<=n;i++)
printf("%d ",data[i]);
printf("\n");
count++;
}
else
{
for(i=k;i<=n;i++)
{
swap(data[k],data[i]);
if(k==1 || Place(data,k))
perm(data,k+1,n);
swap(data[i],data[k]);
}
}
}
int main()
{
int i;
int data[20];
printf("请输入n:");
scanf("%d",&n);
for(i=1;i<=n;i++)
data[i]=i;
perm(data,1,n);
printf("共%d组答案\n",count);
return 0;
}