八皇后时间复杂度 回溯_「软帝学院」“八皇后”面试经典算法,你会了吗?...

2007700db4b91cf4ee78749587aa9348.png

八皇后问题,是一个古老而著名的问题,是回溯算法的典型案例。该问题是国际西洋棋棋手马克斯·贝瑟尔于1848年提出:在8X8格的国际象棋上摆放八个皇后,使其不能互相攻击,即任意两个皇后都不能处于同一行、同一列或同一斜线上,问有多少种摆法。 高斯认为有76种方案。1854年在柏林的象棋杂志上不同的作者发表了40种不同的解,后来有人用图论的方法解出92种结果。

求解过程:

采用遍历的办法,就是采用将每种情况都验证的办法最终找出问题的解,但是蛮力遍历的话,需要遍历的数据量太大,计算时间花费太大,所以在遍历的过程中使用回溯法去掉许多不可能的分支,使问题的规模减小许多。

一个可行解可以这样表示,用一个数组pos[N](N表示皇后的个数,八皇后即为8)表示每一行的皇后应该放在第几列。从将第一个棋子放在第1行的第1列开始一直遍历完这个棋子固定在这个位置的所有解,然后再将第一行的棋子固定在第一行的第二列,再次遍历完所有的解,直到第一行的棋子放在最后的一列,再遍历完,那么所有的解就都找出来了。因为程序代码中已经注释非常详细,所以这里不再重复注释了。程序代码如下:

#include

#include

using namespace std;

#define N 4 /*设置棋盘宽度*/

char pos[N]; /*每一行的这一个棋子放置的位置:0~7*/

bitset stat[N]; /*每一行的空闲位置(除去被行列对角线冲突的位置)*/

bitset mask[N][N]; /*保存回溯过程中以前的状态,因为在对每一行回溯时当时的状态都不一样

所以这个单元的大小是stat的N倍,以便保存N行各自的初始状态*/

int g_count; /*统计有多少种解法*/

void print() /*打印出当前的可行解*/

{

int i, j;

cout<

for(i=0; i < N; i++)

{

for(j=0; j < pos[i]; j++)

cout<

cout<

for(j=pos[i]+1; j < N; j++)

cout<

cout<

}

}

void queen(int n) /*皇后问题求解函数*/

{

int i, j;

if(~stat[n] == 0) /*如果这一行没有空闲位置,这个分支求解失败*/

return;

for(i=0; i < N; i++)

{

if(!stat[n].test(i)) /*test(i)测试第i个bit是否为1,为1返回ture*/

{

pos[n] = i;

if(n+1 == N) /*找到一个解*/

{

print();

g_count++;

return;

}

for(j=n+1; j < N; j++)

{

mask[n][j] = stat[j]; /*进行新的遍历前保存当前未探测行的空闲状态*/

/*从j=n+1开始保存,前面j=0~n的位置已经保存过了,再保存意义也不大*/

stat[j].set(i); /*纵向标记非空闲位置*/

if(i+j-n < N) stat[j].set(i+j-n); /*正对角线方向标记非空闲位置*/

/*正对角线直线方程:I=kN+b(k=1)->i=n+b->b=i-n==>i-n+j即表示新的I值*/

if(i+n-j >= 0) stat[j].set(i+n-j); /*反对角线方向标记非空闲位置*/

/*反对角线直线方程:I=kN+b(k=-1)->i=-n+b->b=i+n==>-(j)+i+n即表示新的I值*/

}

queen(n+1); /*本行探测完毕,进行下一行的探测*/

for(j=n+1; j < N; j++)

stat[j] &= mask[n][j]; /*探测失败,回退(返回上一次的状态)*/

}

}

}

int main(int argc, char* argv[])

{

int i,j;

g_count=0;

for(i=0;i

stat[i].reset();

for(i=0; i < N; i++)

for(j=0; j < N; j++)

mask[i][j].reset();

cout<

queen(0);

cout<

system("pause");

return 0;

}

程序运行结果截图:

124b1852f95c9cd5f78d8cb701d64bd7.png

最后,开发这么多年我也总结了一套学习Java的资料,如果你在技术上面想提升自己的话,可以关注我,私信发送领取资料或者在评论区留下自己的联系方式,有时间记得帮我点下转发让跟多的人看到哦。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值