N皇后问题

来源:互联网 发布:程序员的统计学 编辑:程序博客网 时间:2024/06/06 17:52

转自百度文库


问题:

题目来源于国际象棋的玩法,因为皇后所在的位置可以纵向、横向、两个斜向四个方向的“捕捉”,所以8皇后问题就是要求如何布置8个皇后在8*8的棋盘上而使他们互相无法“捕捉”。也就是说不存在两个皇后同行或同列,或在同一斜线上。而N皇后问题就是如何布置N个皇后在N*N棋盘里使不存在两个皇后在同行同列和同一斜线上


题解:

给棋盘的行和列都编上1到N的号码,皇后也给编上1到N的号码。由于一个皇后应在不同的行上,为不失一般性,可以假定第i个皇后将放在第i行上的某列。因此N皇后问题的解空间可以用一个N元组(X1,X2,.....Xn)来表示,其中Xi是放置皇后i所在的列号。这意味着所有的解都是N元组(1,2,3,.......,N)的置换。解空间大小为N!。其次我们看约束条件:因为解空间已经给我们排除了不在同一行(因为每个皇后分别已经对应不同的行号)的约束条件。我们要判断的是不在同一列和不在同一斜线的约束。因为Xi表示皇后所在的列号,所以如果存在X(k)=X(i)那么肯定存在第k个皇后和第i个皇后同列。所以不同列的判段条件是X(k)!=X(i),1<k<i 。又因为同一斜线的特征是要么行号和列号之和不变(右高左低)要么是行号和列号只差相等(左高右低),所以同斜线的判断条件是 i+X(i)=  k+X(k) 或 i-X(i) =k-X(k),两式合并得 |X(i)-X(k)|=|i-k|  。


        编程基本思路:X(j)表示一个解的空间,j表示行数,里面的值表示可以放置在的列数,抽象约束条件得到能放置一个皇后的约束条件(1)X(i)!=X(k);(2)abs(X(i)-X(k))!=abs(i-k)。应用回溯法,当可以放置皇后时就继续到下一行,不行的话就返回到第一行,重新检验要放的列数,如此反复,直到将所有解解出。


代码:

#include<cstdio>#include<cmath>#include<cstring>using namespace std;int f[20];//f[i]=j,表示在第i行第j列放置一个皇后,相当于压缩成一维bool put_suitable(int k){ //判断当前第k行在第f[k]列放置一个皇后是否合理,所以需要跟之前的所有行的皇后进行比较,判断是否有冲突 for (int i = 1; i <k ; i++) { if (f[i]==f[k] || abs(f[i]-f[k])==abs(i-k))//PS:今天才知道fabs是求实数的绝对值,abs是求int型的绝对值= = { return false; } } return true;//如果所有行都满足情况,那么当前放置情况是合理的}int main(){int n,i,k;int num;while (scanf("%d",&n)!=EOF){num=0;memset(f,0,sizeof(f));k=1;f[k]=0;//k表示当前搜索到第k行while (k>0)//如果回溯到k=0的话,表明所有的情况都试完了,就可以跳出循环了{f[k]++;//当前第k行从小到大开始搜索列数while (  f[k]<=n  &&  !put_suitable(k)  )//表明在搜索到第n列之前,如果不满足当前f[k]列放置一个皇后的话,就搜索下一列,直至搜到符合情况或把n列都搜完{f[k]++;}if (f[k]<=n)//说明在n列内找到了一个可行的情况{if (k==n)//说明搜到最后一行,那就是找到了一个完整的解{num++;for ( i = 1; i <=n ; i++){printf("%d ",f[i]);//输出}printf("\n");}else{k++;f[k]=0;//如果不到最后一行,那就继续往下搜索,重新初始化新一行}}else{k--;//说明没有可行解,就回溯到上一行重新往下搜}}printf("%d\n\n",num);}return 0;}


原创粉丝点击