八皇后问题详细解法

来源:互联网 发布:mac如何设置手机铃声 编辑:程序博客网 时间:2024/06/08 20:06

问题描述:

8×8的棋盘上,放置8皇后(棋子),使两两之间互不攻击。所谓互不攻击是说任何两个皇后都要满足:

1)不在棋盘的同一行;

2)不在棋盘的同一列;

3)不在棋盘的同一对角线上。

求:8个皇后中的每一个应该摆放在哪一列。

算法分析:

数组ColumnDownUp分别用来标记冲突,Column数组代表列冲突,从Column[1]~Column[8]代表第1列到第8列,如果某列上已经有皇后,则为1,否则为0;

  数组Down代表主对角线冲突,为Down[i-j+7](行号-列号+7),主对角线共有15条,即从b[0]~b[14],如果某条主对角线上已经有皇后,则为1,否则为0;

  数组Up代表从对角线冲突,为Up[i+j](行号加列号),从对角线也有15条,即从c[0]~c[14],如果某条从对角线上已经有皇后,则为1,否则为0;

其中主对角线中行i和列j相减的规律如下图所示:


从图中可以看出,每条主对角线上的值相同且相互之间不重复,因此可以将其看成一个标志进行判断。同理,观察次对角线中行i和列j中的值,他们相加的规律如下图所示:


利用这一规律判断对角线的情况。

1)需要在棋盘的( i, j ) 位置摆放一个皇后的时候,可以通过Column数组、Down数组和Up数组的相应元素,来判断该位置是否安全;
2)当已经在棋盘的( i, j ) 位置摆放了一个皇后以后,就应该去修改Column数组、Down数组和Up数组的相应元素,把相应的列和对角线设置为不安全。
3)最后根据递归回溯的方法来实现本问题的目标。
实现函数如下:
int Queen[9]={0};//第i行皇后所在的列;int Column[9]={0};//第j列是否安全,{0, 1}int Down[15]={0};  //记录每一条从上到下的对角线,是否安全,{0,1}int Up[15]={0};//记录每一条从下到上的对角角线,是否安全,{0,1}int num=0;//记录解的个数void TryQueen(int i)// 摆放第 i 行的皇后{if(i<9){for(int j=1;j<9;j++)// 尝试把该皇后放在每一列{if(Column[j]||Down[i-j+7]||Up[i+j-2])continue; // 失败Queen[i]=j;// 把该皇后放在第j列上Column[j]=1;Down[i-j+7]=1;Up[i+j-2]=1;if(i==8)  // 已找到一种解决方案{num++;for(int k=1;k<9;k++)cout<<setw(3)<<Queen[k];cout<<endl;}elseTryQueen(i+1);    // 摆放第i+1行的皇后Queen[i]=0;           // 回溯,把该皇后从第j列拿起Column[j]=0;Down[i-j+7]=0;Up[i+j-2]=0;}}}



原创粉丝点击