八皇后问题是一个经典的问题。问题的描述就是:在国际象棋棋盘上(8*8)放置八个皇后,使得任意两个皇后之间不能在同一行,同一列,也不能位于同于对角线上。问共有多少种不同的方法,并且指出各种不同的放法。这个题的思路,可能,首先让人想到的就是穷举法,这样就需要8重循环,这个能做,但是,有点慢,如果,我们改为n皇后问题呐,这个方法就不适用了。有一个算法思想很适合这个问题的求解,就是“摸着石头过河”的图的遍历中的深度优先算法,这个思想就是,先随便往下去走,如果遇到死胡同,就返回上一级,在寻找其他出路。如果,先从第一行开始放皇后,以此满足条件的放下去,当遇到皇后没地方放的情况,就返回上一行,调整上一行的放的位置,在尝试下一行,这样下去,就会找到出路。这个的算法实现可以用循环,也可以用递归。
循环:
#include<stdio.h>
#include<stdlib.h>
#include<math.h>
void output(int *a,int n)
{
int i;
for(i=1;i<=n;i++)
{
printf("%d ",a[i]);
}
printf("\n");
}
int check(int *a,int n)
{
int i;
for(i=1;i<n;i++)
{
if((abs(a[i]-a[n])==abs(i-n))||(a[i]==a[n]))//a[i]表示第i个皇后所在的列;这个是判断是否在对角线(在对角线的话就是一个斜率为1和-1的直线,所以用abs绝对值)和同一列
{
return 0;
}
}
return 1;
}
int main()
{
int n,i,k;//n皇后问题,第k个皇后;
scanf("%d",&n);
int a[n+1];//a数组里面就是每个皇后的列坐标;
k=1;a[k]=0;
while(k>0)
{
a[k]=a[k]+1;
while((a[k]<n+1)&&(check(a,k)==0))
{
a[k]++;
}
if(a[k]<n+1)
{
if(k==n)
{
output(a,n);
}else
{
k++;
a[k]=0;
}
}else{
k--;//回朔,返回到上一个皇后;
}
}
return 0;
}
递归:
//八皇后问题回朔解法;
#include<stdio.h>
#include<stdlib.h>
int a[20],b[20],c[40],d[40];//a[i]是第i个皇后,b[i]是第i列,c[i]是第i条负对角线,d[i]是第i条主对角线;
int n;
void output(int *a,int n)
{
int i;
for(i=0;i<n;i++)
{
printf("%d ",a[i]);
}
printf("\n");
}
void t(int i)//第i个皇后;
{
int j;
for(j=0;j<n;j++)//第j列;
{
if((b[j]==0)&&(c[i-j+n-1]==0)&&(d[i+j]==0))
{
a[i]=j;
b[j]=1;
c[i-j+n-1]=1;
d[i+j]=1;
if(i<n)
{
t(i+1);
}
else
{
output(a,n);
}
b[j]=0;
c[i-j+n-1]=0;
d[i+j]=0;
}
}
}
int main()
{
printf("输入皇后数:\n");
scanf("%d",&n);
int i;
for(i=0;i<n;i++)
{
a[i]=0,b[i]=0;
c[i]=0,c[n+i]=0;
d[i]=0,d[n+i]=0;
}
t(0);
return 0;
}
这个使用的是用数组表示对角线:
这个图就是八皇后的棋盘,黄色的线就是负对角线,蓝色的就是主对角线,如何表示这些线那,我们用数组中的每一个值表示一条线,这就需要,可以用行数和列数表示这一条线上的所有点,我们将行作为函数中的y值,列作为x值,这样主对角线的可以表示为i=-j+A(A为常数),负对角线的就是i=j+A(A为常数,为了在数组中表示A可能是负数,所以加上一个有关行数或者列数的数,)这就是上面的关于数组表示对角线的道理。