赞
踩
【问题引入】
在8×8格的国际象棋上摆放8个皇后,使其不能互相攻击,即任意两个皇后都不能处于同一行、同一列或同一斜线上,问有多少种摆法。高斯认为有76种方案。1854年在柏林的象棋杂志上不同的作者发表了40种不同的解,后来有人用图论的方法解出92种结果。如果经过±90度、±180度旋转,和对角线对称变换的摆法看成一类,共有42类。计算机发明后,有多种计算机语言可以编程解决此问题。
【问题分析】
本题将要用到的是一种回溯的思想,为了更方便解释,先来看一道四皇后问题,也就是在4X4的棋盘上放四个皇后
首先,有一个4X4的棋盘
我们用星星来表示皇后,首先将一个皇后放置(0,0)位置,红色的位置就不能再放置皇后,绿色位置还可以放置
那么接下来进行下一次放置,我们放置在(1,2)位置
此时我们发现,第二行已经无法放置皇后,本题中每一行每一列都应该有且仅有一个皇后,所以这种情况不符合条件
若将第二个皇后放在(1,3)位置
第二行还有一个位置可以放,那么继续
此时发现最后一行已经无法放置皇后,因此位置(0,0)不能放置皇后
接下来重新开始放置,将第一个皇后放置在(0,1)位置
第0行的皇后放在了(0,1)位置,那么第一行的皇后只能放在(1,3)位置
接下来第三个皇后放在(2,0)位置
第四个皇后只能放置在(3,2)位置
此时发现已经完成了四皇后要求,讲图案进行旋转变换,很容易得到四皇后的第二种解法
可以验证一下,四皇后问题有且仅有这两种解法
这是回溯算法的一个利用,那么接下来就是八皇后问题的代码
- #include<stdio.h>
-
- int sum = 0; //方法总数
- int chess[8][8]={0}; //8*8的棋盘
-
- //判断此次放置是否合理|合理则返回1,否则返回0
- int check(int row,int col)
- {
- int i,j;
- for (i = 0; i < 8; i++) //判断皇后所在列
- {
- if (chess[i][col] == 1)
- return 0;
- }
- for (i = row, j = col; i >= 0 && j >= 0; i--, j--) //判断左下对角线
- {
- if (chess[i][j] == 1)
- return 0;
- }
- for (i = row, j = col; i >= 0 && j < 8; i--, j++) //判断右下对角线
- {
- if (chess[i][j] == 1)
- return 0;
- }
- return 1;
- }
- //打印输出结果
- void print()
- {
- int i,j;
- printf("第%d种解法\n",sum+1);
- for (i = 0; i < 8; i++)
- {
- for (j = 0; j < 8; j++)
- {
- if (chess[i][j] == 1)
- printf("Q "); //皇后放置位置输出‘Q’
- else
- printf("# "); //其余位置输出‘#’
- }
- printf("\n");
- }
- printf("\n");
- }
- //寻找解法
- void search(int row)
- {
- if (row == 8) //此时0-7行均已正常放置皇后
- {
- print();
- sum++;
- return;
- }
- int col; //列
- for (col = 0; col < 8; col++) //假定将皇后放置在第row行第col列
- {
- if (check(row, col)) //若可以放置在此
- {
- chess[row][col] = 1; //修改该元素值为1
- search(row + 1); //进行下一次递归
- chess[row][col] = 0; //恢复被修改的值,否则会影响后续递归
- }
- }
- }
-
- int main()
- {
- search(0);
- printf("共有%d种解法\n",sum);
- return 0;
- }
八皇后问题官方答案是92种解法
此代码还可以延伸到N皇后,但时间复杂度很高,运行时间较长。N=10时有724种解法,运行时间已经非常长了,若N=12,有14200种解法,可能需要运行数分钟
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。