n皇后问题

Problem Description
在N*N的方格棋盘放置了N个皇后,使得它们不相互攻击(即任意2个皇后不允许处在同一排,同一列,也不允许处在与棋盘边框成45角的斜线上。
你的任务是,对于给定的N,求出有多少种合法的放置方法。

考虑每行只能放一个皇后,每列也只能放一个皇后,那么如果把N列皇后所在的行号依次写出,那么就会是1~n的一个排列。

因此就只需要枚举1~n的所有排列,查看每个排列的放置方案是否合法,统计其中合法的方案即可。
总共有n!个排列。

于是可以在全排列的代码基础上进行求解,由于当到达递归边界时表示生成了一个排列,所以需要在其内部判断是否为合法方案,即遍历两个皇后,判断它们是否在同一条对角线上(不在同一行和同一列是显然的),若不是,则累计计数变量count即可。代码如下:

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

const int maxn = 11;
//P为当前排列, hashTable记录整数x是否已经在p中
int n, P[maxn], hashTable[maxn] = {false};

int cnt = 0;

void generateP(int index){
	if(index == n + 1){ //递归边界,生成一个排列 
		bool flag = true; //flag为true,表示当前排列为一个合法方案 
		
		/*
			在二维数组中,处在同一对角线上的两个元素
			它们的 |行下标相减| == |列下标相减| 
		*/
		for(int i = 1; i <= n; i++){ //遍历任意两个皇后 
			for(int j = i + 1; j <= n; j++){
				// 行相减            列相减 
				if(abs(i - j) == abs(P[i] - P[j])){ //如果在同一条对角线上 
					flag = false;
				}
			}
		}
		
		if(flag)cnt++; //方案合法 +1 
	
		return;
	}
	
	//我们从下标为1的位置 开始填 这样对应的位置更加直观一些 
	for(int x = 1; x <= n; x++){ 
		if(!hashTable[x]){
			P[index] = x; 
			hashTable[x] = true; 
			generateP(index + 1); 
			hashTable[x] = false; 
		}
	}	
} 

int main(){
	n = 8; 
	generateP(1);	
	
	cout << cnt << endl;
	return 0; 
}

下面是回溯法

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

const int maxn = 11;
//P为当前排列, hashTable记录整数x是否已经在p中
int n, P[maxn], hashTable[maxn] = {false};

int cnt = 0;

void generateP(int index){
	if(index == n + 1){ //递归边界,生成一个合法方案 
		cnt++;  //能达到这里的一定是合法的
		 
		return;
	} 
			
	for(int x = 1; x <= n; x++){ //第x行 
		if(!hashTable[x]){ //第x行没有皇后 
			bool flag = true; //为true时 表示当前皇后不会和之前的皇后冲突 
			for(int pre = 1; pre < index; pre++){
				//第index列皇后的行号为x,第pre列皇后的行号为P[pre]
				if(abs(index - pre) == abs(x - P[pre])){
					flag = false; //与之前的皇后在一条对角线上,冲突 
					break;
				} 
			} 
		
			if(flag){ //如果可以吧皇后放在第x行 
				P[index] = x; //令第index列皇后的行号为x
				hashTable[x] = true; //第x行已经被占用
				generateP(index + 1); //递归处理第 index + 1行皇后
				hashTable[x] = false; //递归完毕,还原第x行为 未占用 
			} 
		}
	}	
} 

int main(){
	n = 8; 
	generateP(1);	
	
	cout << cnt << endl;
	return 0; 
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值