n个皇后放置问题

点击查看代码
/* 
n个皇后放置问题:
在一个n*n的国际象棋棋盘上放置n个皇后,使得这n个皇后两两均不在同一行、同一列、同一条对角线上,求合法的方案数 
*/
#include<cstdio>
#include<cmath> //使用abs()
#pragma warning(disable:4996)

const int maxn = 11;
//P[i]=x表示第i列皇后的行号是x,HashTable[x]记录第x行是否已放置皇后,如果是则为true
int n, P[maxn], HashTable[maxn] = { false };
int count = 0; //统计合法方案数

/*
1、暴力法:
使用传统方法枚举所有情况,判断每种情况是否合法
处理当前排列的第index位,P[i]=x表示第i列皇后的行号是x
*/
void generateP(int index) {
	//递归边界,排列的1~n位已经处理完,可以输出
	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 == true) count++; //如果flag为true,则合法方案count加一
		return; //结束递归返回上一层
	}
	//枚举1~n,将x存入P[index]中
	for (int x = 1; x <= n; x++) { 
		//如果x还没存入P[0]~P[index-1]中,则本轮可以将x存入
		if (HashTable[x] == false) { 
			P[index] = x; //将x存入P[index]中
			HashTable[x] = true; //x已在P[]中
			generateP(index + 1); //处理当前排列的第index+1位
			HashTable[x] = false; //已经处理完P[index]为x的子问题,HashTable[x]要还原为false,留作下次使用
		}						  
	}
}	

/*
2、回溯法:
当已经放置了一部分皇后时(生成了一个排列的一部分),如果此时剩余的皇后不管怎样放置都会与现有皇后在同一对角线上,
那么就不需要再继续向下递归,可以提前结束返回上一层,减少计算量
*/
void generateP(int index) {
	//递归边界,生成一个合法方案
	if (index == n + 1) { 
		count++;
		return;
	}
	//第x行
	for (int x = 1; x <= n; x++) { 
		//第x行还没有皇后
		if (HashTable[x] == false) { 
			bool flag = true; //flag为true表示当前皇后与之前的皇后没有冲突
			//将当前准备放置的皇后与之前的所有皇后比较,判断是否在同一对角线上
			for (int pre = 1; pre < index; pre++) {	 
				//第index列皇后的行号为x,第pre列皇后的行号为P[pre]
				if (abs(index - pre) == abs(x - P[pre])) { //如果列号之差等于行号之差,则两个皇后在同一对角线
					flag = false; //当前准备放置的皇后与之前的pre皇后在同一对角线上,该方案不合法,不用再继续向下递归
					break; //结束循环
				}
			}
			if (flag == true) {	 //当前准备放置的皇后与之前的皇后不冲突,则可以放置
				P[index] = x; //第index列皇后的行号是x
				HashTable[x] = true; //第x行已被占用
				generateP(index + 1); //递归处理第index+1行皇后
				HashTable[x] = false; //递归完成,还原第x行未被占用
			}
		}
	}
}			  

int main() {
	n = 8; //n=8(有8个皇后),合法方案数count=92
	generateP(1); //从P[1]开始填充数字
	printf("%d", count);
	return 0;
}

posted @ 2022-09-27 22:51  zhaoo_o  阅读(6)  评论(0编辑  收藏  举报