关于N皇后问题

来源:互联网 发布:视频合并软件 安卓版 编辑:程序博客网 时间:2024/05/21 15:02

解法一:

主要是比较传统的方法,采用二维数组的方式来记录N皇后的位置:

#include<iostream>
using namespace std;
#define N  4
int a[N][N];  //记录每个节点的值 即判断皇后可以放的位置 
int nodej[N]; //记录每次存放的行的列位置的下一个点的位置  用它记录 来达到回溯的效果

bool canPlace(int a[N][N] , int row , int col)
{
 int i , j;
 for(i = 0 ; i < N ; i++)
 {
  if(a[row][i] == 1 && i != col)
   return false;
  if(a[i][col] == 1 && i != row)
   return false;
 }
 for(i = row + 1 , j = col + 1 ; i < N && j < N ; i++ , j++)
  if(a[i][j] == 1)
   return false;
 for(i = row -1 , j = col - 1 ; i >= 0 && j >= 0 ; i-- , j--)
  if(a[i][j] == 1)
   return false;
 for(i = row + 1 , j = col - 1 ; i < N && j >= 0 ; i++ , j--)
  if(a[i][j] == 1)
   return false;
 for(i = row - 1 , j = col + 1 ; i >= 0 && j < N ; i-- , j++)
  if(a[i][j] == 1)
   return false;
 return true;

}
void print(int a[N][N])
{
 int i , j;

 cout<<"----------------------------------"<<endl;
 for(i = 0 ; i < N ; i++)
 {
  for(j = 0 ; j < N ; j++)
   if(a[i][j] == 0)
    printf("%4c",'*');
   else
    printf("%4c",'@');
  cout<<endl;
 }

}
void main()
{
 int flag = 1;
 int count = 0;
 for(int i = 0 ; i < N ;)
 {
  int j = nodej[i];
  for(; j < N ;)
  {
   if(canPlace(a , i , j))
   {
    a[i][j] = 1;
    nodej[i] = j + 1; //记录现在存放节点的下一个位置
    break;
   }
   j++;
   if(j == N)//判断是否可回溯  以及回溯后产生的效果
   {
    int t = i - 1;
    while(t >= 0)
    {
     if(nodej[t] < N)
     {
      
      a[t][nodej[t] - 1] = 0;
      nodej[t + 1] = 0;  //注意: 这是个易错点,利用t的变化性,来多次来改变nodej的值
      i = t - 1;//i的值多减,后面for循环会++
      break;
     }
     else if(nodej[t] == N)
     {
      a[t][nodej[t] - 1] = 0;
      nodej[t + 1] = 0;
      t--;
     } 
    }
    if(nodej[0] == N && t == -1)//记录最后一次,首节点不能再回溯了,并且以它为首的其他节点,不能再回溯
     flag = 0;
   } 
  }
  i++;
  if(i == N )//for循环在全部回溯完之后,再多执行一次,然后跳出
  {
   if(nodej[0] == N && flag == 0)
    break;
   if(flag)
   {
    count++;
    print(a);
   }
   int t = i - 1;
   while(t >= 0)
   {
    if(nodej[t] < N)
    {
     i = t;    //i已经在前面进行+1操作
     a[t][nodej[t] - 1] = 0;
     break;
    }
    else if(nodej[t] == N)
    {
     a[t][nodej[t] - 1] = 0;
     nodej[t] = 0;
     t--;
    } 
   }
  }
 }
 cout<<"一共有: "<<count<<"中方法。"<<endl;
}

 

 

解法二:

比较节省空间的方法,很巧妙的利用了数组和它的值来进行对N皇后位置的确定:

#include<iostream>
using namespace std;
#define N 4
int x[N];

bool abs(int x,int y)
{
 if(x == y || x == -y || -x == y || -x == -y)
  return true;
 else
  return false;
}
bool canPlace(int k) //比较好的布局法  很巧妙的利用了数组和它的值的对应关系
{
 int i = 0;
 while(i < k)
 {
  if(x[i] == x[k] || abs(x[i] - x[k] , i - k))
   return false;
  i++;
 }
 return true;
}

void print(int x[])
{
 int i = 0;
 cout<<"--------------------------------"<<endl;
 while(i < N)
 {
  for(int j = 0 ; j < N ; j++)
  {
   if(j == x[i])
    printf("%4c",'!');
   else
    printf("%4d", 0);
  }
  cout<<endl;
  i++;
 }
}

void main()
{
 int count = 0;
 x[0] = -1;
 int k = 0;
 while(k > -1)
 {
  x[k] = x[k] + 1;
  while(x[k] < N && !canPlace(k))//如果不可以的话,会一直的增加 
  {
   x[k] = x[k] + 1;
  }
  if(x[k] < N)
  {
   if(k == N - 1)
   {
    count++;
    print(x);
   }
   else
   {
    k = k + 1;
    x[k] = -1;
   }
  }
  else
   k = k - 1; //不用记录回溯的点,因为上次的值的下一个,就是回溯点
 }
 cout<<"一共有: "<<count<<"中方法"<<endl;
}

 

原创粉丝点击