N皇后问题
Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 5563 Accepted Submission(s): 2518
Problem Description
在N*N的方格棋盘放置了N个皇后,使得它们不相互攻击(即任意2个皇后不允许处在同一排,同一列,也不允许处在与棋盘边框成45角的斜线上。
你的任务是,对于给定的N,求出有多少种合法的放置方法。
你的任务是,对于给定的N,求出有多少种合法的放置方法。
Input
共有若干行,每行一个正整数N≤10,表示棋盘和皇后的数量;如果N=0,表示结束。
Output
共有若干行,每行一个正整数,表示对应输入行的皇后的不同放置数量。
Sample Input
1 8 5 0
Sample Output
1 92 10
思路:
给棋盘的行和列都编上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|
第一次递归代码:超时
#include <stdio.h> #include <stdlib.h> #include <math.h> int sum,x[11]; bool place(int k) { //int i; //printf("k=%d\n",k); //for(i=1;i<=n;i++) printf("%d ",x[i]); // printf("\n"); int j; for(j=1;j<k;j++) { if(abs(j-k)==abs(x[j]-x[k]) || x[j]==x[k] ) return false; //在同一斜线或同一列 } return true; } void backtrack(int t,int n) { int i; // printf("t=%d,n=%d\n",t,n); // for(i=1;i<=n;i++) printf("%d ",x[i]); // printf("\n"); if(t>n) { sum++; // printf("sum=%d\n",sum); } else { for(i=1;i<=n;i++) { x[t]=i; // printf("%d\n",place(t,x)); if(place(t)) backtrack(t+1,n); } } } int main() { int n,i; while(scanf("%d",&n),n) { sum = 0; for(i=1;i<=n;i++) x[i]=0; backtrack(1,n); printf("%d\n",sum); } return 0; }
第二次AC 简单打表,因为是N《= 10 ,因此用1中代码,将N等于1 to10都计算出来,放在一维数组
#include <stdio.h> int main() { int a[11]={0,1,0,0,2,10,4,40,92,352,724}; int n,i; while(scanf("%d",&n),n) printf("%d\n",a[n]); return 0; }
AC代码:15MS 228KB
#include <stdio.h> #include <math.h> #include <iostream> int x[11],cnt[11],n,sum; bool flag; void DFS(int k)//放置第k个皇后 { int i,j,flag; if(k>n) {//放置的皇后个数大于n时,表示一种解决方案 sum++; return; } for(i=1;i<=n;i++)//将第k个皇后依次放在第1 to n列 { flag = 1; x[k] = i;//列値1 to n for(j=1;j<k;j++) //依次与前1到k-1个皇后比较 { if(x[k]==x[j]||abs(j-k)==abs(x[k]-x[j])) {//在同一列或在同一斜线 flag = 0; break; } } if(flag) DFS(k+1);//第k个皇后与前k-1个都比交完,互不冲突再放置第k+1个皇后 } } int main() { for(n=1;n<11;n++) { sum =0; DFS(1); cnt[n] = sum; } while(scanf("%d",&n),n) printf("%d\n",cnt[n]); return 0; }