例题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)
- 输出
- 输出有n行,每行输出对应一个输入。输出应是一个正整数,是对应于b的皇后串。
- 样例输入
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;
}