八皇后
在国际象棋中,皇后是最厉害的棋子,可以横走、直走,还可以斜走。棋手马克斯·贝瑟尔 1848 年提出著名的八皇后问题:即在 8 × 8 的棋盘上摆放八个皇后,使其不能互相攻击 —— 即任意两个皇后都不能处于同一行、同一列或同一条斜线上。
现在我们把棋盘扩展到 n × n 的棋盘上摆放 n 个皇后,请问该怎么摆?请编写程序,输入正整数 n,输出全部摆法(棋盘格子空白处显示句点“.”,皇后处显示字母“Q”,每两格之间空一格)。
看到这里,很容易想到递归。但是这里想要快速写出八皇后,那么先从一个简单的排列开始。
举一个很简单的排列,例如1~5的全排列。顾名思义,就是12345,12435..........以此递推下去。那么最简单,最容易理解的就是用递归。
#include<stdio.h>
//从1~n中任取m个的组合,在排列写法上增加一个剪枝逻辑即可
int X[100],n,m,used[100],cnt=0;
void output()
{
int i;
printf("\n%d: ",++cnt);
for(i=1;i<=m;i++)
printf("%d ",X[i]);
}
int jianzhi(int k,int i)
{
int j;
//增加的剪枝逻辑:x[k]不能小于x[k-1]
if(k>1 && i<X[k-1]) return 0;
if(used[i]) return 0;
return 1;
}
void f(int k)
{ int i;
if(k-1==m) output();
else for(i=n;i>0;i--)//优先用大的元素i
if(jianzhi(k,i))
{
X[k]=i;
used[i]=1;
f(k+1);
used[i]=0;
}
}
int main()
{
scanf("%d%d",&n,&m);
f(1);
return 0;
}
很明显,这里的排序组合,稍微改一下就变成了八皇后问题,只需要将剪枝函数,稍作修改,改成判断这一行,这一列,斜线有没有皇后。就摇身一变成为了八皇后问题。
#include<stdio.h>
int X[100],n,cnt=0;
void output()
{
int i,j;
printf("\n%d: \n",++cnt);
for(i=1;i<=n;i++)
{
for(j=1;j<X[i];j++) printf("* ");
printf("Q ");
for(j=X[i]+1;j<=n;j++) printf("* ");
printf("\n");
}
}
int jianzhi(int k,int i)
{
int j;
for(j=1;j<k;j++)
if(X[j]==i || X[j]-i==j-k || X[j]-i==k-j) //第一个条件判断是否有同列的
return 0;
//第二个条件判断是否有对角的
return 1;
}
void f(int k)
{ int i;
if(k-1==n) output();
else for(i=1;i<=n;i++)
if(jianzhi(k,i))
{
X[k]=i;
f(k+1);
}
}
int main()
{
scanf("%d",&n);
f(1);
return 0;
}
这样通过,一个简单的排序问题,就能解决八皇后问题。