2.王、后传说

问题描述

  地球人都知道,在国际象棋中,后如同太阳,光芒四射,威风八面,它能控制横、坚、斜线位置。
  看过清宫戏的中国人都知道,后宫乃步步惊心的险恶之地。各皇后都有自己的势力范围,但也总能找到相安无事的办法。
  所有中国人都知道,皇权神圣,伴君如伴虎,触龙颜者死......
  现在有一个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; 
} 

猜你喜欢

转载自blog.csdn.net/qq_40636117/article/details/81112402
2.