(蓝桥杯)基础练习BASIC-27 2n皇后问题 (递归) C++

问题描述

  给定一个n*n的棋盘,棋盘中有一些位置不能放皇后。现在要向棋盘中放入n个黑皇后和n个白皇后,使任意的两个黑皇后都不在同一行、同一列或同一条对角线上,任意的两个白皇后都不在同一行、同一列或同一条对角线上。问总共有多少种放法?n小于等于8。

输入格式

  输入的第一行为一个整数n,表示棋盘的大小。
  接下来n行,每行n个0或1的整数,如果一个整数为1,表示对应的位置可以放皇后,如果一个整数为0,表示对应的位置不可以放皇后。

输出格式

  输出一个整数,表示总共有多少种放法。

样例输入

4
1 1 1 1
1 1 1 1
1 1 1 1
1 1 1 1

样例输出

2

样例输入

4
1 0 1 1
1 1 1 1
1 1 1 1
1 1 1 1

样例输出

0

解题思路:首先使用二维数组建立棋盘,在分别定义数组w[maxn]存储白皇后落子情况,b[maxn]存储黑皇后落子情况例如w[3]=1意为白皇后在第三行的落子位置为第一列。逐行递归的落子,每次判断当前落子位置所在的竖列,对角线上是否已有落子,若有则条件不成立,无法落子,进入下一列;若条件成立,则进入下一行,直至完成棋盘遍历,确定最后结果。

对角线的计算方式:数学中的(x1-x2)/(y1-y2)计算斜率,计算结果为1或-1时,对角线倾斜45度/135度,代码中abs();函数作用为计算绝对值

#include<cstdio>
#include<cstring>
#include<cmath>
#define maxn 10
int chess[maxn][maxn];//棋盘 
int w[maxn],b[maxn],n,result=0;//w[maxn]存储白皇后落子情况,b[maxn]存储黑皇后落子情况 
/*检查是否符合落子规则*/ 
bool check(char c,int x){
	char color=c;
	int row=x;
	//若为白皇后,则检查其所在横排、竖列或对角线上是否有同色落子 
	if(color=='w'){
		for(int i=1;i<row;i++){
			if(w[i]==w[row]||abs(w[i]-w[row])==abs(i-row)){
				return false;
			}
		}
	}
	//若为黑皇后,则首先检查该位置上是否已经有白皇后,再检查其所在横排、竖列或对角线上是否有同色落子 
	else{
		for(int i=1;i<row;i++){
			if(b[i]==b[row]||abs(i-row)==abs(b[i]-b[row])){
				return false;
			}
		}
		
	}
	return true;
}
/*黑皇后落子(后)*/ 
queen_b(int row){
	int x=row;
	if(x>n){
		//满足题意,result值+1 
		result++;
	}
	for(int i=1;i<=n;i++){
		if(chess[x][i]==1&&w[x]!=i){
			b[x]=i;
			//检查结果若为真,则落子 
			if(check('b',x)){
				queen_b(x+1);
			}
		}
	}
}
/*白皇后落子(先)*/ 
queen_w(int row){
	int x=row;
	//白皇后落满,黑黄后开始落子 
	if(x>n){
		queen_b(1);
	}
	for(int i=1;i<=n;i++){
		if(chess[x][i]==1){
			w[x]=i;
			//检查结果若为真,则落子
			if(check('w',x)){
				queen_w(x+1);
			}
		}
	}
}

int main(){
	memset(w,0,sizeof(w));
	memset(b,0,sizeof(b));
	memset(chess,0,sizeof(chess));
	scanf("%d",&n);
	for(int i=1;i<=n;i++){
		for(int j=1;j<=n;j++){
			scanf("%d",&chess[i][j]);
		}
	}
	//白皇后先落子,将对应的横行作为参数传递给函数 
	queen_w(1);
	printf("%d",result);
	return 0;
}

  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值