N皇后问题

来源:互联网 发布:苹果乐器软件 编辑:程序博客网 时间:2024/06/05 14:58

根据国际象棋的规则,处在同一列,同一行,同一斜线(与棋盘夹角45°)的 “皇后” 都是可以互相攻击的,那么在8 x 8的标准国际象棋棋盘上可以有多少种情况使8个“皇后”使得他们都无法互相攻击,1848年国际西洋棋棋手马克斯·贝瑟最早提出了这个问题,如下图所示的就是一种4皇后的情况,“X”代表皇后所在位置。,将这个问题扩展开来,在N x N的棋盘上有多少种情况可以让N个皇后和谐相处,是数据结构 与算法的经典问题,本文将给大家分享一下小编对此类问题解法的一些思路。

解题思路:

<一>皇后在落脚之前需要确定四个方向是否有姐妹存在,这四个方向也就是横向、纵向、左斜线、右斜线,所以需要四个数组记录他们。横向和纵向的储存不再讨论,直接利用二维数组的行坐标列坐标记录即可,对于斜方向的情况,如下图所示,左斜方向上的所有位置的横坐标减纵坐标所得整数值是固定的,中心线左侧的值为正,右侧的值为负,通过这一特征,可以判断皇后所在位置aij的 w[j-i+N]是否已经存在来考虑是否可以在此落脚。右下斜向上的所有位置横纵坐标相加的和相等,通过这一特征,可以判断皇后所在位置aij的 w[i+j-2]是否已经存在来考虑是否可以在此落脚。

<二>很多教材和文章都提到,通过递归的方法和对所有情况进行深搜是很有效的方法。深搜的每一层实际上就是棋盘的每一行,递归的函数里对每一行的所有位置进行判断,若<1>中的4种情况均不存在,皇后便在此落脚,否则,皇后将前往下一个位置判断,每次皇后落脚之后都要在这四个位置上登记,证明自己已经在这了,注意:在每次递归完成之后都要恢复现场。sum用来记录已经有多少位皇后已经被安置好,递归结束的条件就是层数>N,符合条件的情况是sum==N,代码如下。

#include<stdio.h>#include<string.h>int w[4][26];int a[13][13];int flag;int answer;void digui(int x,int sum);int main(){while(scanf("%d",&flag),flag){memset(w,0,sizeof(w));memset(a,0,sizeof(a));answer = 0;digui(1,0);printf("answer:%d\n",answer);}return 0;}void digui(int x,int sum){if(x>flag){if(sum == flag){answer ++;return ;}}for(int y=1 ; y<=flag ; y++){if(w[0][y])     continue;if(w[1][y])continue;if(w[2][y-x+9]) continue;if(w[3][x+y-2]) continue;change(x,y,1);digui(x+1,sum+1);change(x,y,0);}}void change(int x,int y,int m){w[0][y] = m;w[1][y] = m;w[2][y-x+9] = m;w[3][x+y-2] = m;a[x][y] = m;}

以下是N在20以内的皇后问题的解的个数,可以在平常练习时进行验证:


                                                                                          相关题目传送门

0 0