计蒜客 - 2n皇后问题

时间限制 1000ms 内存限制 65536K

题目描述

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

输入格式

输入的第一行为一个整数 n,表示棋盘的大小。

接下来 n 行,每行 n  0  1的整数,如果一个整数为1,表示对应的位置可以放皇后,如果一个整数为 0,表示对应的位置不可以放皇后。

输出格式

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

样例输入1
4
1 1 1 1
1 1 1 1
1 1 1 1
1 1 1 1
样例输出1
2
样例输入2
4
1 0 1 1
1 1 1 1
1 1 1 1
1 1 1 1
样例输出2
0

【思路】

       这道题可以看成是两个八皇后问题,我们可以先把所有的黑皇后放入棋盘中的合适位置,这里用和正常八皇后问题的递归函数求解即可,然后在黑皇后全部放入的情况下尝试放入白皇后,当所有的白皇后都可被放入时即存在一组解。只是这里判断有无冲突的函数bool notDanger(int r, int c)有所区别,对于黑皇后而言,除了当前位置不能与之前的皇后同列同斜线以外,这个位置必须是可放位置,即chess[r][c]==1,对白皇后同理,而且白皇后不能处于和已经放好的黑皇后相同的位置上面去。

 

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;

int n, ans;
int chess[10][10];
int x1[10], x2[10];
//先放入黑皇后,再放入白皇后

bool notDanger1(int r, int c) {//判断黑皇后是否冲突
	if (0 == chess[r][c]) return false;
	for (int i = 0; i < r; i++) {
		if (x1[i] == c) return false;
		if (abs(r - i) == abs(c - x1[i])) return false;
	}
	return true;
}

bool notDanger2(int r, int c) {//判断白皇后是否冲突
	if (0 == chess[r][c]) return false;
	if (x1[r] == c) return false;//注意黑白皇后不能重叠
	for (int i = 0; i < r; i++) {
		if (x2[i] == c) return false;
		if (abs(r - i) == abs(c - x2[i])) return false;
	}
	return true;
}

void queen2(int k) {//在第k行放入白皇后
	if (k == n) {
		ans++;
		return;
	}
	for (int i = 0; i < n; i++) {
		if (notDanger2(k, i)) {
			x2[k] = i;
			queen2(k + 1);
			x2[k] = -1;
		}
	}
}

void queen1(int k) {//在第k行放入黑皇后
	if (k == n) {
		queen2(0);
		return;
	}
	for (int i = 0; i < n; i++) {
		if (notDanger1(k, i)) {
			x1[k] = i;
			queen1(k + 1);
			x1[k] = -1;
		}
	}
}

int main() {
	while (scanf("%d", &n) == 1) {
		ans = 0;
		memset(x1, -1, sizeof(x1));
		memset(x2, -1, sizeof(x2));
		for (int i = 0; i < n; i++) {
			for (int j = 0; j < n; j++)
				scanf("%d", &chess[i][j]);
		}
		queen1(0);
		printf("%d\n", ans);
	}
	return 0;
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值