解法一:
主要是比较传统的方法,采用二维数组的方式来记录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;
}