今天突然看到了这一个问题:
用分支限界法求解四皇后问题,要求输出四皇后问题的所有可行解,我以前都是用贪心法写的,所以花了一段时间去看待这个
大家可以先写写看
先思考:
。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。
分析:
我们可以用一串数字来表示问题的解,比如[2,4,1,3] 表示 4×4 棋盘的4皇后问题的解,第一行的棋子摆在第2列;第二行的棋子摆在第4列,依此类推
,可以看出,某一行的棋子摆了之后,棋子的那一列肯定不能再摆其他的棋子了,
所以解[x,x,x,……,x] 一定是 1-n 的一个全排列,
所以这里的解空间树我们选择排列树。
思路:
既然已经确定了要用排列树来作为问题的解空间树,接下来要确定的就是剪枝函数了。
剪枝函数只要从已经摆好的棋子的第一个开始遍历,依此判断下面的棋子是否在其攻击范围内即可,
因为我们之前没有在同一行摆多个棋子,也没有在同一列摆多个棋子,所以只要判断其他棋子是否在其斜线上的攻击范围即可,比如
。。3 。
1 。。。
。。。4
。2 。。
3到一方向,3到4方向
第一行的棋子摆在第3列上,只要沿图中方向判断即可,既可以得到结果。
。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。
代码如下:如有分析不妥当之处,还请大佬们及时指正,谢谢大家。
#include<iostream>
#include<ctime>
using namespace std;
bool isOK(int n, int pieces[])
{ //剪枝函数
//判断当前状态是否合理,即皇后会不会互相攻击
for (int i = 1; i <= n-1; i++)
{
for (int j = i + 1; j <= n; j++)
{
int left = -(j - i);//向左的斜线
int right = (j - i);//向右的斜线
if (pieces[j] == pieces[i] + left||pieces[j] == pieces[i] + right)
{//第i行皇后和第j行皇后会互相攻击
return false;
}
}
}
//所有皇后都不会互相攻击
return true;
}
void swap(int &a, int &b)
{
int t = a;
a = b;
b = t;
}
void nQueen(int n, int t, int pieces[])
{
if (t > n)
{
for (int i = 1; i <= n; i++)
{
for (int j = 1; j < pieces[i]; j++)
cout << "- ";
cout << pieces[i]<<" ";
for (int j = pieces[i] + 1; j <= n; j++)
cout << "- ";
cout << endl;
}
cout << endl;
}
else
{
for (int i = t; i <= n; i++)
{
swap(pieces[t], pieces[i]);
if (isOK(t, pieces))
{
nQueen(n, t + 1, pieces);
}
swap(pieces[t], pieces[i]);
}
}
}
int main()
{
int n;
cin >> n;
int *pieces = new int[n + 1];
for (int i = 1; i <= n; i++)
{
pieces[i] = i;
}
nQueen(n, 1, pieces);
cout << "OK" << endl;
system("pause");
}