八皇后问题

八皇后问题是一个经典的问题。问题的描述就是:在国际象棋棋盘上(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可能是负数,所以加上一个有关行数或者列数的数,)这就是上面的关于数组表示对角线的道理。

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值