问题描述:
在n×n格的棋盘上放置彼此不受攻击的n个皇后。按照国际象棋的规则,皇后可以攻击与之处在同一行或同一列或同一斜线上的棋子。
N后问题等价于再n×n的棋盘上放置n个皇后,任何2个皇后不可以在同一行或同一列或同一斜线上。
输入:
给定棋盘的大小n (n ≤ 13)
输出:
输出有多少种放置方法。
解题思路:
要解决N皇后问题,其实就是要解决好怎么放置这n个皇后,每一个皇后与前面的所有皇后不能在同一行、同一列、同一对角线,在这里我们可以以行优先,就是说皇后的行号按顺序递增,只考虑第i个皇后放置在第i行的哪一列,所以在放置第i个皇后的时候,可以从第1列判断起,如果可以放置在第1个位置,则跳到下一行放置下一个皇后。如果不能,则跳到下一列…直到最后一列,如果最后一列也不能放置,则说明此时放置方法出错,则回到上一个皇后向之前放置的下一列重新放置。此即是回溯法的精髓所在。当第n个皇后放置成功后,即得到一个可行解,此时再回到上一个皇后重新放置寻找下一个可行解…如此后,即可找出一个n皇后问题的所有可行解。
//n皇后 回溯法 这里是将数组x模拟为二维数组,这里的列不会重复,只需要判定行和对角线是否会重复
class Queen
{
friend int Nqueen(int n);//该类的友元函数
private:
//x[m]=n表示从第m列的从上往下数第n个元素,这个很重要,将一维的变为二维
bool Place(int k)//该函数用来判断该皇后是否处于合适位置
{
for (int i = 0; i < k; ++i)
{
if ( (x[i] == x[k]) || (abs(x[i] - x[k]) == abs(i - k)))//如果插入的元素和之前已插入元素在同一行或者同一列,则不能插入,返回false
{
return false;
}
}
return true;
}
void Backtrack(int i)
{
if (i == n)
{
for (int r = 0; r < n;++r)
{
for (int c = 0; c < n;++c)//按行打印
{
if (x[c] == r)
{
cout << "Q" << " ";
}
else
{
cout << "#"<<" ";
}
}
cout << endl;
}
cout << endl;
sum += 1;
}
else
{
//j=0 x[0],x[1],x[2],x[3]=0;每一列的第一行
for (int j = 0; j < n; ++j)
{
x[i] = j;//按列放入
if (Place(i))
{
Backtrack(i+1);
}
}
}
}
int n;//n后问题
int *x;//数组名
int sum;//皇后最多几种摆放
};
int Nqueen(int n)
{
Queen Q;
Q.n = n;
Q.sum = 0;
Q.x = new int[n];
for (int i = 0; i < n; ++i) Q.x[i] = 0;//数组全置为0
Q.Backtrack(0);//从第0列开始
delete[]Q.x;
return Q.sum;
}
void main()
{
int sum;
int n;
cin >> n;
sum = Nqueen(n);
cout <<"皇后最多种摆放个数" <<" "<<sum<< endl;
}