八皇后问题 _ 递归枚举排列法

递归枚举排列法

//生成排列递归法源代码、思路来自:《算法竞赛入门经典》第二版的 P185 、 P192
//八皇后问题初试
//根据8个皇后在不同行不同列
//步骤:填第一行的皇后、填第二行的皇后(不能与之前的同列)、...、填第八行的皇后
//相当于 枚举排列:01234567表示 每行皇后(0,1,2,...,7)所在的列数
//排列出一个后,判断是否处于对角线的 
//2020/3/31
#include <iostream>
#include <cstring>
#include <cmath>

using namespace std;

const int k = 8;	//k皇后求解 
int g_count = 0; 

void Permu(int n,int *A,int cur) {
	if (cur == n) {
//		for (int i = 0; i < k; i++) {
//			cout << A[i];
//		}
//		cout << endl;
		//判断是八皇后否在一个对角线上
		bool is_true = true;
		for (int i = 0; i < n; i++) {
			for (int j = i+1  ; j < n; j++) {
				int r = fabs(i-j);		//行列的差值若相同,则处于同一对角线上 
				int c = fabs(A[i] - A[j]);
				if (r * c > 0 && r == c) {
					is_true = false;
				} 
			}
		} 
		if (is_true) {
			g_count++;
			for (int i = 0; i < k; i++) {
				for (int j = 0; j<k; j++) {
					if (j == A[i]) {
						cout << "Q";
					}
					else
						cout << "*";
				}
				cout << endl;
			}
			cout << "______________分割线\n";
		}
	}
	else {
		for (int i = 0; i < k; i++) {	//往A[i]中尝试 0-7 的各种数
			int is_ok = true; 
			for (int j = 0; j < cur; j++) {
				if (i == A[j]) is_ok = false;
			}
			if (is_ok) {
				A[cur] = i;
				Permu(k,A,cur+1); 
			}
		}
	}
}

int main() {
	int A[k];
	Permu(k,A,0);
	cout << "Total number = " << g_count << endl; 
	return 0;
}

在递归函数中加入判断条件后(咱也不知道这算不算回溯法)

根据紫书所说,回溯法就是在递归的同时也进行判断,不符合K皇后条件的枚举不展开结点了,直接回到上一步调用。

例如:递归到 排列 01,此时其实已经不符合条件了(处于同一对角线),没必要继续展开了,直接返回上一步,这样可以省下一大笔功夫

这就是回溯法,在递归的基础上进行优化的算法。

我比较了一下两种算法的运行时间,哇,递归法在K = 11时候已经等半天都出不来结果(运行了37.92s),回溯法秒出结果(0.17s)。

这优化的可不是一点点呐,算法真的太强了!哇!

/*
增加递归判断,实现回溯法 
*/ 

//八皇后问题初试
//根据8个皇后在不同行不同列
//步骤:填第一行的皇后、填第二行的皇后(不能与之前的同列)、...、填第八行的皇后
//相当于 枚举排列:12345678表示第i(1-8)行皇后在第i(式子里分别代入)列 
//排列出一个后,判断是否处于对角线的 
//2020/3/31
#include <iostream>
#include <cstring>
#include <cmath>

using namespace std;

const int k = 11;	//k皇后求解 
int g_count = 0; 

void Permu(int n,int *A,int cur) {
	if (cur == n) {
//		for (int i = 0; i < k; i++) {
//			cout << A[i];
//		}
//		cout << endl;
		//判断是八皇后否在一个对角线上
		bool is_true = true;
		for (int i = 0; i < n; i++) {
			for (int j = i+1  ; j < n; j++) {
				int r = fabs(i-j);		//行列的差值若相同,则处于同一对角线上 
				int c = fabs(A[i] - A[j]);
				if (r * c > 0 && r == c) {
					is_true = false;
				} 
			}
		} 
		if (is_true) {
			g_count++;
//			for (int i = 0; i < k; i++) {
//				for (int j = 0; j<k; j++) {
//					if (j == A[i]) {
//						cout << "Q";
//					}
//					else
//						cout << "*";
//				}
//				cout << endl;
//			}
//			cout << "______________分割线\n";
		}
	}
	else {
		bool is_legal = true;	//判断是否继续递归的代码段,若不满足皇后条件,则回溯 
		for (int i = 0; i < cur; i++) {
			for (int j = i+1  ; j < cur; j++) {
				int r = fabs(i-j);		//行列的差值若相同,则处于同一对角线上 
				int c = fabs(A[i] - A[j]);
				if (r * c > 0 && r == c) {
					is_legal = false;
				} 
			}
		}
		if (!is_legal) return;	//直接回溯,不要递归下去了 
		
		for (int i = 0; i < k; i++) {	//往A[i]中尝试 0-7 的各种数
			int is_ok = true; 
			for (int j = 0; j < cur; j++) {
				if (i == A[j]) is_ok = false;
			}
			if (is_ok) {
				A[cur] = i;
				Permu(k,A,cur+1); 
			}
		}
	}
}

int main() {
	int A[k];
	Permu(k,A,0);
	cout << "Total number = " << g_count << endl; 
	return 0;
}
发布了41 篇原创文章 · 获赞 2 · 访问量 1638

猜你喜欢

转载自blog.csdn.net/qq_44296342/article/details/105215520