n皇后问题

n皇后问题其实就是一个全排列问题,列的顺序固定下,第一列可选择全部行,第二列可选择剩余的n-1行,一直到最后一列选择仅剩的最后一行的一个全排列,当到达递归终点时,表明一个全排列已经结束,然后开始检查这个全排列是否合法,不合法就立即返回,合法就计数加一。

等所有可能的排列都走尽时,得到的计数就是所有可能的结果了。

代码如下:

bool isUsed[maxSize] = {false}; //表明这个数字(行号)是否被用过
int p[maxSize] = {0}; //存储排列的数组

int n; //n皇后问题
int count = 0; //总计数

void nQueueProblem(int index){ //index表示当前进行的是排列中的第index位选择
	if(index == n + 1){
		bool flag = true;
		for(int i = 1 ; i <= n ; ++i) {
		bool needBreak = false; //内层循环判断非n皇后排列时,可以直接跳出外层循环
		for (int j = i + 1; j <= n; ++j)
			if (abs(i - j) == abs(p[i] - p[j])) { //对角线就是任意和主对角线或副对角线平行的线,这个公式涵盖了所有对角线情况
				flag = false;
				needBreak = true;
				break;
			}
			if(needBreak)
			break;
		}
		if(flag)
			++count;
		return ;
	}

	for(int i = 1 ; i <= n ; ++i){
		if(isUsed[i] == false){ //如果当前数字i还未使用也即行号i还未选择过
			p[index] = i; //选择i,也即排列中index位选择第i行
			isUsed[i] = true; //数字i已经用过了(行号i已经选择过了)
			nQueueProblem(index+1); //继续排列中下一个空位的选择
			isUsed[i] = false; //返回后数字i重新回归未用过的集合中
		}
	}
}

int main(int argc, const char * argv[]) {
	cin >> n;
	nQueueProblem(1);
	cout << count;
}

以上方法还有改进的空间,比如第一次排列的结果是123456789…n,这个排列显然是对角线式的不满足n皇后条件,而且从2开始就已经不满足了,因为剩余后面的各种组合都是无效组合,因此可以在递归的过程中进行优先排定剔除掉不可能的排列,以节省大量无效操作提高效率:

代码如下:

void nQueueProblem(int index){
	if(index == n + 1){ //安全的到达最后一步,表明形成的已经是一个n皇后的排列了
		++count;
		return;
}
	for(int i = 1; i <= n ; ++i){
		if(isUsed[i] == false) {
			bool flag = true; //先假定这个数字是可用的,也即这个数字加入排列后不会破坏n皇后条件
			for(int pre = 1 ; pre < index ; ++pre) //检查这个数字是否真的可用,也即假设当前选用了i后,看是否会破坏n皇后条件
			if(abs(pre - index) == abs( i - p[pre])){ //如果加入了数字i(选用了行号i)破坏了n皇后条件
				flag = false;
				break;
			}

			if (flag) { //如果这个数字(或称为行号)真的是可用的
				p[index] = i; //使用这个数字,将其放入排列
				isUsed[i] = true;
				nQueueProblem(index + 1);
				isUsed[i] = false;
			}
		}
	}
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值