【n后问题】“回溯法”——《算法设计与分析(第五版)》


一、算法要求

在nxn格的棋盘上放置彼此不受攻击的n个皇后。按照国际象棋的规则,皇后可以攻击与之处在同一行或同一列或同一斜线上的棋子。n后问题等价于,在nxn格的棋盘上放置n个皇后,任何2个皇后不放在同一行或同一列或同一斜线上。

1. 思路

在第i行第j列放置一个皇后,那么第i行的其他位置(同行),那么第j列的其他位置(同列),同一斜线上的其他位置,都不能再放置皇后。

可以以行为主导:
·在第1行第1列放置第1个皇后。
·在第2行放置第2个皇后。第2个皇后的位置不能和第1个皇后同列、同斜线,不用再判断是否同行了,因为每行只放置一个,本来就已经不同行。
·在第3行放置第3个皇后,第3个皇后的位置不能和前2个皇后同列、同斜线。
……
·在第t行放置第t个皇后,第t个皇后的位置不能和前t-1个皇后同列、同斜线。
……
·在第n行放置第n个皇后,第n个皇后的位置不能和前n-1个皇后同列、同斜线。

2. 示例

在这里插入图片描述


二、完整代码

1. 主文件

main.cpp:

// Project2: n后问题

#include<iostream>
#include<iomanip>
#include<cmath>
using namespace std;

const int numMax = 1000;
int n,			//n个皇后
	countn = 0,		//可行解的个数
	x[numMax];	//放置在第i行第x[i]列

bool Place(int t) {	//判断第t个皇后能否放置在第i个位置
	bool opt = true;
	for (int j = 1; j < t; j++) {//判断是否与已放置的皇后冲突
		if (x[t] == x[j] || fabs(t - j) == fabs(x[t] - x[j])) {
			opt = false;
			break;
		}
	}
	return opt;
}

void Backtrack(int t) {
	if (t > n) {//成功
		countn++;

		//打印结果
		cout <<"#No." << countn << ": ";
		for (int i = 1; i <= n; i++) {
			cout << setw(3) << x[i];
		}
		cout << endl;
	}
	else
		for (int i = 1; i <= n; i++){//分别判断n个分支
			x[t] = i;
			if (Place(t))
				Backtrack(t + 1); 
		}
}
int main() {
	cout << "#Please enter the number of queens(n): "; 
	cin >> n;
	cout << "\n#The conditions are as follows: " << endl;
	Backtrack(1);

	cout << "\n#The number of answers is: " 
		<< countn << endl; 
	return 0;
}


2. 效果展示

在这里插入图片描述


三、补充

算法复杂度分析:
(1)时间复杂度
n皇后问题的解空间是一棵m (m=n)叉树,树的深度为n。最坏情况下,除了最后一层外,有1+n+n2 +…+nn-1=(nn-1)(n-1)~nn-1个结点需要扩展,而这些结点每个都要扩展n个分支,总的分支个数为nn,每个分支都判断约束函数,判断约束条件需要O(n)的时间,因此耗时O(nn+1)。在叶子结点处输出当前最优解需要耗时O(n),在最坏情况下回搜索到每一个叶子结点,叶子个数为nn,故耗时为O(nn+1)。因此,时间复杂度为O(nn+1)。

(2)空间复杂度
回溯法的另一个重要特性就是在搜索执行的同时产生解空间。在所搜过程中的任何时刻,仅保留从开始结点到当前扩展结点的路径,从开始结点起最长的路径为n。程序中我们使用x[]数组记录该最长路径作为可行解,所以该算法的空间复杂度为O(n)。

文档供本人学习笔记使用,仅供参考。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

NI'CE'XIAN

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值