例题1:百练 2754
描述
会下国际象棋的人都很清楚:皇后可以在横、竖、斜线上不限步数地吃掉其他棋子。如何将8个皇后放在棋盘上(有8 * 8个方格),使它们谁也不能被吃掉!这就是著名的八皇后问题。对于某个满足要求的8皇后的摆放方法,定义一个皇后串a与之对应,即a=b1b2...b8,其中bi为相应摆法中第i行皇后所处的列数。已经知道8皇后问题一共有92组解(即92个不同的皇后串)。给出一个数b,要求输出第b个串。串的比较是这样的:皇后串x置于皇后串y之前,当且仅当将x视为整数时比y小。
输入
第1行是测试数据的组数n,后面跟着n行输入。每组测试数据占1行,包括一个正整数b(1 <= b <= 92)
2 1 92
15863724 84136275
分析:主要是满足条件分析:
其中A[cur]==A[j]是判断皇后是否会纵向攻击:
其中cur-A[cur]==j-A[j]||cur+A[cur]==j+A[j]语句的意思是:皇后(cur,A[cur])和皇后(j,A[j])是否在同一对角线上:
判断的原理如图所示:
0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 |
-1 | 0 | 1 | 2 | 3 | 4 | 5 | 6 |
-2 | -1 | 0 | 1 | 2 | 3 | 4 | 5 |
-3 | -2 | -1 | 0 | 1 | 2 | 3 | 4 |
-4 | -3 | -2 | -1 | 0 | 1 | 2 | 3 |
-5 | -4 | -3 | -2 | -1 | 0 | 1 | 2 |
-6 | -5 | -4 | -3 | -2 | -1 | 0 | 1 |
-7 | -6 | -5 | -4 | -3 | -2 | -1 | 0 |
(a) 格子(x,y)的y-x值标志了主对角线
0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 |
1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 |
2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 |
3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 |
4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 |
5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 |
6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 |
7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 |
(b)格子(x,y)的y+x值标志了副对角线
用x表示行,y表示列,则有x1=cur,y1=A[cur]:X2=j;y2=A[j];
根据图中的数值关系,可知在同一主对角线满足:cur-A[cur]==j-A[j];在同一副对角线满足:cur+A[cur]==j+A[j]
#include<iostream> using namespace std; int A[10],num=1,B[100][10]; int DFS(int cur) { if(cur==8) { for(int i=0;i<8;i++) B[num][i]=A[i]; num++; } else for(int i=0;i<8;i++) { int flag=1; A[cur]=i+1; for(int j=0;j<cur;j++) if(A[cur]==A[j]||cur-A[cur]==j-A[j]||cur+A[cur]==j+A[j]) {flag=0;break;} if(flag) DFS(cur+1); } } int main() { int n,m; cin>>n; DFS(0); while(n--) { cin>>m; for(int i=0;i<8;i++) cout<<B[m][i]; cout<<endl; } return 0; }
题2:Tyvj 1080(N皇后),需要剪枝利用use[2][]直接判断当前的皇后所在列和两个对角线是否有其他的皇后,注意主对角线标志y-x可能为负,所以存储的时候要+n。
#include<iostream> #include<cstdio> #include<cstring> using namespace std; const int MAX=15; #define CLR(arr,val) memset(arr,val,sizeof(arr)) int n,sum,A[MAX],use[MAX][2*MAX]; void DFS(int cur) { if(cur==n) { sum++; if(sum<=3) { for(int i=0;i<n;i++) printf("%d ",A[i]); printf("\n"); } } else { for(int i=0;i<n;i++) if(!use[0][i]&&!use[1][cur+i]&&!use[2][cur-i+n])//use[0][i]判读当前皇后所在列是否存在其它皇后 { A[cur]=i+1; use[0][i]=use[1][cur+i]=use[2][cur-i+n]=1; //used[1][cur+i]为副对角线 DFS(cur+1); use[0][i]=use[1][cur+i]=use[2][cur-i+n]=0; //use[2][cur-i+n]为主对角线 } } } int main() { while(scanf("%d",&n)!=EOF) { sum=0; DFS(0); CLR(use,0); printf("%d\n",sum); } return 0; }