问题描述
地球人都知道,在国际象棋中,后如同太阳,光芒四射,威风八面,它能控制横、坚、斜线位置。
看过清宫戏的中国人都知道,后宫乃步步惊心的险恶之地。各皇后都有自己的势力范围,但也总能找到相安无事的办法。
所有中国人都知道,皇权神圣,伴君如伴虎,触龙颜者死......
现在有一个n*n的皇宫,国王占据他所在位置及周围的共9个格子,这些格子皇后不能使用(如果国王在王宫的边上,占用的格子可能不到9个)。当然,皇后也不会攻击国王。
现在知道了国王的位置(x,y)(国王位于第x行第y列,x,y的起始行和列为1),请问,有多少种方案放置n个皇后,使她们不能互相攻击。
输入格式
一行,三个整数,皇宫的规模及表示国王的位置
输出格式
一个整数,表示放置n个皇后的方案数
样例输入
8 2 2
样例输出
10
数据规模和约定
n<=12
分析:
本来是个n皇后问题,放个国王来搞什么鬼呢
既然题目这么要求了,就按要求好了。
定义数组house[20][20],令其值全为0,表示可以进入
1、设置国王禁地:
为了省去数组边界判断,横向从 house[y][0] 到 house[y][n] ,纵向 house[1][x] 到 house[1][n]
这样可以放心地给国王位置 house[y][x] 及其周边8格拉起警戒线。
把这九个格子的数值设置成-1,表示生人勿进
3、王后的放置
为了方便管理,我们从上往下给每一行放置一个王后,如果一行有两个王后,那么就冲突了
2、王后的攻击范围及安全位置
王后的攻击范围有垂直攻击 “|” ,左斜攻击 “\” ,右斜攻击 “/”
用数组a[n],b[n],c[n]分别存储王后的攻击范围
先用8x8的棋盘来分析,Q表示皇后位置,X表示攻击范围,O表示非攻击范围:
1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | |
1 | O | O | O | Q | O | O | O | O |
2 | O | O | X | X | X | O | O | O |
3 | O | X | O | X | O | X | O | O |
4 | X | O | O | X | O | O | X | O |
5 | O | O | O | X | O | O | O | X |
6 | O | O | O | X | O | O | O | O |
7 | O | O | O | X | O | O | O | O |
8 | O | O | O | X | O | O | O | O |
如果y行x列上放置一个皇后
那么从y+1行到第8行的x列上,只要是列数=x,就在这个王后垂直攻击范围内
y+n行的x-n列,都是其左斜攻击范围,只要行数-列数=y-x,就在这个王后左斜攻击内,
令b[y-x]=-1,表示所有左斜攻击范围(y+1行的x-1列,y+2行的x-2列。。。y+n行的x-n列);
y+n行的x+n列,都是其右斜攻击范围,只要行数+列数=y+x,就在其左斜攻击内。同上,令c[x+y]=-1;
同时我们发现,b[n],c[n]是不够用的
数组b:-6<x-n<=6 数组c:0<x+n<=12 跨度都是2n,所以应为b[2n],c[2n]
假设一个王后在d行e列上安全,那么
house[d][e]!=-1,不在国王范围内
a[e]!=-1,即垂直方向上不被其他的王后攻击到
b[d-e]!=-1,即不在任何王后左斜攻击内
c[d+e]!=-1,即不在任何王后右斜攻击内
3、递归与回溯
设棋盘长宽为N
设函数Quee(n)用来给每层放置皇后,n表示某层
①、如果第n层可以放置王后且n<=N,那么递归Quee(n+1),给下一层放置王后
②、如果从house[n+1][1]到house[n+1][N]都无法放置皇后,说明第n层放王后的地方不对。那么Quee(n+1)递归结束,
撤销Quee(n)原本放置的王后(设放在n行i列上),取消她的攻击范围,即
house[n][i]=0;a[i]=0;b[n+i]=0;c[n-i]=0;
从而实现回溯
然后再把王后放在n行的i+1列上(i+1<=N)。(若i+1>N,继续取消上一层放王后的地方)
所以递归和回溯为:
Quee(n+1);
house[n][i]=0;a[i]=0;b[n+i]=0;c[n-i]=0;
可以放王后,Quee(n+1)一路递归直到最后一层;反之撤销王后的放置的位置再重新放
代码:
#include<stdio.h>
#include<stdlib.h>
int house[20][20],big,x,y;
int a[20],b[40],c[40];//竖排攻击,右斜攻击,左斜攻击
int total=0;
void Quee(int n){
if(n>big){
++total;
}else{
for(int i=1;i<=big;++i){
if(house[n][i]==0 && a[i]!=-1 && b[n+i]==0 && c[n-i]==0){
//不在任何皇后竖向,左斜或右斜攻击内,也不在国王范围内
house[n][i]=-1;a[i]=-1;b[n+i]=-1;c[n-i]=-1;//设置皇后攻击范围和皇后位置
Quee(n+1);//递归下一层
//无法继续往下递归了,不管怎么放下一层都在攻击范围内
//说明这一层皇后放错位置了,要取消这一层皇后的位置和攻击范围
house[n][i]=0;a[i]=0;b[n+i]=0;c[n-i]=0;
}
}
}
}
int main(){
scanf("%d %d %d",&big,&x,&y);
for(int i=0;i<=big;++i){
for(int j=0;j<=big;++j){
house[i][j]=0;
}
}
//皇宫横向从house[1][1]到house[1][n],
//纵向从house[1][1]到house[n][1],
//就不用判断国王是否在皇宫边上了
house[x][y]=-1;house[x-1][y]=-1;house[x+1][y]=-1;house[x-1][y-1]=-1;house[x][y-1]=-1;
house[x+1][y-1]=-1;house[x-1][y+1]=-1;house[x][y+1]=-1;house[x+1][y+1]=-1;
//皇家禁地
Quee(1);
printf("%d",total);
return 0;
}