八皇后问题--回溯

在刘汝佳老师的书中对于8皇后问题的分析(我感觉非常经典):

8皇后问题可行的解:92个

回溯的定义: 当把问题分解成若干的步骤并递归的求解时候,如果当前步骤没有合法的选择,则函数将返回上一级递归调用,这种现象称为回溯。这是这个原因,递归枚举算法常被称为回溯法,应用十分普遍。

一共有3种思考的出发点:

  1. 从64个格子中选一个子集,使得”子集中恰好有8个格子,且任意两个选出的格子都不在同一行,同一列或同一对角线上”,这正是子集的枚举问题。然而,64个格子的子集有264个,太大了,这并不是一个很好的模型
  2. 从64个格子中选8个格子,这是组合生成问题。根据组合数学,有c864 种方案,但是任然是不够好的
  3. 经过思考,不难发现以下的事实:恰好每行每列各放置一个皇后 。如果使用c[x]表示第x行皇后的列编号,则问题就变成了全排列问题。而0-7的全排列共有8!个,枚举的量是不会超过它。

上代码:

#include<iostream>
#include<math.h>
using namespace std;
int a[8][8]; //相当于放置八个皇后的棋盘 
int dfs(int n);  //深度优先搜索 
bool isOk(int m,int n); //判断(m,n)位置上是否可以放置一个皇后 
int count = 0; //用于记录总的可行的解的数量 
int main(){
	dfs(0);
	cout  << count;
}
int dfs(int n){ //第几层的皇后 
	if (n > 7){
		for (int i=0; i<8; i++){
			for (int j=0; j<8; j++)
				cout << " " << a[i][j];
			cout << endl; 
		}
		count++;
		cout << endl;
		return 0;
	}
	for (int i=0; i<8; i++){
		if (isOk(n,i)){ //判断该位置是否可以放置 
			a[n][i] = (n+1);
			dfs(++n);
			--n;  //考虑该行棋盘的其他位置的时候,将环境还原 
			a[n][i] = 0;
		}
	}
}

bool isOk(int m,int n){
	if (a[m][n] == 0){
		for (int i=0; i<8; i++){
			for (int j=0; j<8; j++){
				if (a[i][j] != 0){
					if (abs(m-i) == abs(n-j)|| i==m || j==n)
						return false;
				}
			}
		}	
	}else{
		return false;
	}
	return true;
}

8皇后问题可行的解:92个

回溯的定义: 当把问题分解成若干的步骤并递归的求解时候,如果当前步骤没有合法的选择,则函数将返回上一级递归调用,这种现象称为回溯。这是这个原因,递归枚举算法常被称为回溯法,应用十分普遍。

下面是书中的代码:

书中的代码使用的是一位数据就解决的问题:

#include<iostream>
//使用一维数组解决问题
using namespace std; 
int c[8]; 
int n=8; //代表的是8个皇后,同时是8维的棋盘 
void search(int cur);
int tot = 0;
int main(){
	search(0);
	cout <<tot; 
}

void search(int cur){//cur标志的是现在正在处理的是第几个皇后 
	if (cur == n){
		tot ++;  //tot代表的是可行解的总数量 
	}else{
		for (int i=0; i<n; i++){ //对于每个皇后都要考虑一行的8个位置 
			int ok = 1;
			c[cur] = i;
			for (int j=0; j<cur; j++) //检查和前面的皇后是否冲突 
			if (c[cur]==c[j] || cur-c[cur]==j-c[j] || cur+c[cur]==j+c[j]){
				ok = 0;
				break; 
			} 
			if(ok)
			search(cur+1);
		}
	} 
}
    原文作者:八皇后问题
    原文地址: https://blog.csdn.net/u012155875/article/details/52565831
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞