N皇后问题

/*
  Name: N皇后问题 
  Description:八皇后问题是一个古老而著名的问题,是回溯算法的典型例题。
  该问题是十九世纪著名的数学家高斯1850年提出:在8*8格的国际象棋棋盘上,
  安放八个皇后,要求没有一个皇后能够“吃掉”任何其他一个皇后,
  即任意两个皇后都不能处于同一行、同一列或同一条对角线上,求解有多少种摆法。
  高斯认为有76种方案。1854年在柏林的象棋杂志上不同的作者发表了40种不同的解,
  后来有人用图论的方法得出结论,有92种摆法。 
*/
#include<iostream>
using namespace std;

class Queen
{
      friend int nQueen(int n);
      public:
             void Print(int *x);
             void Backtrack();
             bool Place(int k);
      protected:
      private:
              int n;//皇后的个数
              int *x;//当前解
              int sum;//当前已找到的可行方案数 
};

int nQueen(int n)
{
    Queen X;
    X.n = n;
    X.sum = 0;
    
    int *p = new int[n+1];
    for(int i = 0;i <= n;i++)
            p[i] = 0;
    X.x = p;
    X.Backtrack();
    delete [] p;
    return X.sum;
}
//==================判断同一行,列,斜线是否有其他的皇后======================

bool Queen::Place(int k)
{
     for(int j = 1;j < k;j++) 
     {
             //因为数组的下标即为该皇后所在的列值.故不可能出现同列的皇后 
             //如果行差的绝对值等于列差的绝对值或者行相等
             //即说明在同一斜线或着是在同一行 
             if((abs(k-j) == abs(x[j]-x[k]))||(x[j] == x[k]))
             {
                          return false;
             }
     }
     return true;
}
 
//==================进行迭代回溯============================================ 

void Queen::Backtrack()
{
     x[1] = 0;//数组第一个值为0,初始化 
     int k = 1;//用k来标记数组下标 
     while(k > 0)//k>0代表向下有可能寻找到解,
     // k等于0代表向下寻不到解往后回溯一直回溯到根节点往下还没有寻找到解的可能
     //也就是说再寻找已经没有解了   
     {
             x[k] += 1;//行数加一
             //如果行数在指定的范围内,并且有冲突 
             while((x[k]<=n)&&!(Queen::Place(k)))
             {
                   x[k] += 1;//把该皇后向下移一个位置,再进行判断 
             }
             if(x[k] <= n)//如果已经找到了一行,在这行上的皇后和之前的皇后都不冲突 
             {
                     if(k == n)//如果此时是最后一列的皇后找到了满足条件的行数,
                     //即已经找到了一个解决方案 
                     {
                          sum++;//当前可行的方案数加一 
                          Queen::Print(x);//将这个方案打印出 
                     }
                     else//如果此时寻找到合适位置的不是最后一列的皇后 
                     {
                         k++;//列数加一,寻找下一列的皇后应该在的合适行数 
                         x[k] = 0;//这个行数暂定为0,
                         //(先初始化这个行数,找到这个行数后再把这个行数写进去,
                         //如果该列的皇后没找到合适的行数,那么该列的行数就是0 
                     } 
             } 
             else//如果在该列上没找到适合的行数,那么就退回上一列,重新往下再找一个满足条件的行 
             k--;//列数减一,及后退一列
     }
} 
void Queen::Print(int *x)
{
     for(int i = 1;i <= n;i++)//逐行 
     {
             for(int j = 1;j <= n;j++)//逐列 
             {
                     if(i == x[j])//如果在该列保存的值等于行值,说明这应该有一个皇后 
                     {
                          cout << 'X' << ' ';
                     }
                     else
                     cout << '0' << ' ';
             }
             cout << '\n';
     }
     cout << '\n';
} 
//==================执行N皇后问题==================================== 
void operate()
{
     cout << "==========请输入要执行的操作:==========" << endl; 
     cout << "==========0.不执行操作=================" << endl;
     cout << "==========1.执行N皇后问题==============" << endl;
     
     int m;
     cin >> m;
     switch(m)
     {
              case 0:break;
              case 1:
                   {
                           cout << "请输入皇后的个数:" ;
                           int n;
                           cin >> n;
                           cout << "下面是执行过程:" << endl;
                           int i = nQueen(n);
                           cout << "共有:" << i << "种解法!" <<endl;
                           operate();
                           break;
                   }
              default:
                      {
                           cout << "请输入正确的操作!" <<endl;
                           operate();
                      }
     }
}
//==========================主函数,调用nQueen()函数================================ 
int main()
{
	cout << "现有N×N的棋盘,放入N个皇后,要求所有皇后不在同一行、列和同一斜线上!" << '\n';
	operate();
}

你可能感兴趣的:(n皇后问题)