回溯(八皇后问题)

来源:互联网 发布:网络诈骗多少金额受理 编辑:程序博客网 时间:2024/05/04 17:46

回朔是设计递归算法的重要方法,通常采用深度优先搜索(DFS)

算法提出:

在国际象棋棋盘上(8*8)放置八个皇后,使得任意两个皇后之间不能在同一行,同一列,也不能位于同于对角线上。问共有多少种不同的方法,并且指出各种不同的放法。

算法思路:

  首先我们分析一下问题的解,我们每取出一个皇后,放入一行,共有八种不同的放法,然后再放第二个皇后,同样如果不考虑规则,还是有八种放法。于是我们可以用一个八叉树来描述这个过程。从根节点开始,树每增加一层,便是多放一个皇后,直到第8层(根节点为0层),最后得到一个完全八叉树。  

  紧接着我们开始用深度优先遍历这个八叉树,在遍历的过程中,进行相应的条件的判断。以便去掉不合规则的子树。

  用X[i]来表示,在第i行,皇后放在了X[i]这个位置。

  于是我们考虑第一个条件,不能再同一行,同一列于是我们得到x[i]不能相同。剩下一个条件是不能位于对角线上,这个条件不是很明显,我们经过分析得到,设两个不同的皇后分别在j,k行上,x[j],x[k]分别表示在j,k行的那一列上。那么不在同一对角线的条件可以写为abs((j-k))!=abs(x[j]-x[k]),其中abs为求绝对值的函数。

  于是下面我们便可以利用一个递归的调用来遍历八叉树。

  递归有两个重要点:

        1.如何通过有限的步骤, 来解决最小的问题,这里最小的问题就是:找到了这样一种方法必须要计数sum++;其次要把这种排列方式打印出来X[]数组分别记录了在第一行,这个数是多少。所以我们打印一个8*8的矩阵,每一行进行遍历,若j=x[i],则该位置打印1,其余位置打印0

其程序如下:

if(t>n)
   {
        sum++;
        for(int i=1;i<=n;i++)
          {
      for(int j=0;j<n;j++)
             {
                 if(j==x[i]-1)
                      cout<<1<<" ";
                 else
                     cout<<0<<" ";
            }
           cout<<endl;
        }
   }

 2.通过将问题切分成有限小并更小的子问题,需要把8个,只需要先摆好一个,再调用摆其他7个,就这样一直探索下去。当每次探索结束之后又会回到之前的那个地方。这里同时加入判断条件,当满足判断条件,才进行探索

else
  {
      for(int i=1;i<=n;i++)
      {
           x[t]=i;//摆棋
           if(place(t)) backtract_queen(t+1);
      }
  }

所以整体为:

void backtract_queen(int t)
{
   if(t>n)
   {
     sum++;
     for(int i=1;i<=n;i++)
     {
      for(int j=0;j<n;j++)
         {
            if(j==x[i]-1)
               cout<<1<<" ";
            else
               cout<<0<<" ";
        }
           cout<<endl;
      } 
   }
   else
   {
      for(int i=1;i<=n;i++)
      {
          x[t]=i;
          if(place(t)) backtract_queen(t+1);
      }
   }
}

2.条件判断语句:两个皇后不能再同行同列,也不能在同一对角线

bool place(int k)
{
for(int j=1;j<k;j++)//前面已经讲过了都是一行一行摆放的,所以不会同一行
{
if((abs(x[j]-x[k])==abs(j-k))||(x[j]==x[k]))//(x[j]==x[k])表示不会再同一列,abs(x[j]-x[k])==abs(j-k)行列相等
return false;
}
return true;
}

完整程序:

#include<iostream.h>
#include<math.h>
int sum=0;//用于统计解的个数
int n;//表示皇后的个数
int *x;//解向量


void backtract_queen(int t)
{
   if(t>n)
   {
     sum++;
     for(int i=1;i<=n;i++)
     {
      for(int j=0;j<n;j++)
       {
         if(j==x[i]-1)
            cout<<1<<" ";
        else
            cout<<0<<" ";
       }
            cout<<endl;
      }
       
      
   }
   else
   {
      for(int i=1;i<=n;i++)
      {
        x[t]=i;
        if(place(t)) backtract_queen(t+1);
      }
   }
}
int main()
{
   cout<<"input the number of queen:";
   cin>>n;
   x=new int[n+1];
   backtract_queen(1);
   cout<<"sum="<<sum<<endl;
   return 0; 
}

原创粉丝点击