整理 - n皇后问题(递归法 & 回溯法)

递归法

递归应该按照分析出“大问题”、“小问题”写出递归模型写出递归算法的步骤进行考虑。

  • 递归函数为queen(i, n),表示“在i ~ n行的某一列放置剩下的n-i+1个皇后”(即,在n~1-i行上已经放好了i-1个皇后);
  • queen(i, n)是“大问题”,queen(i+1, n)是“小问题”。
  • 这里用伪代码表示递归模型:
if (i > n)
	n个皇后放置完毕,输出一个解;
else
{
	在第i行找到一个合适的位置(i, j),放置一个皇后;
	queen(i+1, n);
}
  • 完整代码
#include<iostream>
#include<cmath>
#include<cstring>
#define maxn 10
int q[maxn+1];  //存放各皇后所在的列号,即(i, q[i])为一个皇后的位置 
				//为了简便,不使用索引为0的行/列位置 
int count = 0;  //累计可行解的个数 
using namespace std;  

bool place(int i, int j) //测试(i, j)位置能否摆放皇后 
{
	if (i == 1)			 //第一个皇后可以放置到每一列,所以直接返回true 
		return true;
	for (int k = 1; k < i; k++)//与已放置了皇后的行进行比较、判断
		if (q[k] == j || (abs(q[k] - j) == abs(k - i)))  
			return false;
	return true;
}

void queen(int i, int n)
{
	if (i > n)
	{
		count += 1; 
		for (i = 1; i <= n; i++)
			printf("(%d, %d)", i, q[i]);
		cout << endl;
	} 
	else 
		for (int j = 1; j <= n; j++) //在第i行上试探每一个列j 
			if (place(i, j)) 
			{
				q[i] = j;
				queen(i+1, n);					
			}
}

int main()
{
	int n;
	cin >> n;
	memset(q, 0, sizeof(q));
	queen(1, n);//放置1 ~ n个皇后 
	cout << "可行解个数:" << count;
	return 0;
}

回溯法

  • 回溯算法是有框架的,应该深刻理解并记住框架,然后灵活套用。
  • 本题用到的解题框架是:递归回溯框架之解空间为子集树的情况。(请自行想象出本题的子集树…)
    在这里插入图片描述
#include<iostream>
#include<cmath>
#include<cstring>
#define maxn 10
using namespace std; 
int n;
int q[maxn+1];  //存放各皇后所在的列号,即(i, q[i])为一个皇后的位置 
				//为了简便,不使用索引为0的行/列位置 
int count = 0;  //累计可行解的个数 

bool place(int i) //判断第i行的q[i]列能否摆放皇后 
{
	if (i == 1)			 		//第一个皇后可以放置到每一列,所以直接返回true 
		return true;
	for (int k = 1; k < i; k++) //与已放置了皇后的行进行比较、判断
		if (q[k] == q[i] || (abs(q[k] - q[i]) == abs(k - i)))  
			return false;
	return true;
}
void backtrack(int i)
{
	if (i > n) //搜索到叶子结点(根结点为第一层时,叶子结点为第n+1层,所以此处判断条件为i > n),输出一个可行解 
	{
		count += 1; 
		for (int x = 1; x <= n; x++)
			printf("(%d, %d) ", x, q[x]);
		cout << endl;		
	}
	else 
	{
		for (int j = 1; j <= n; j++)//用j枚举i所有可能的路径
		{
			q[i] = j;				//产生一个可能的解分量 
			if(place(i)) 			//q[i]满足约束条件 
				backtrack(i+1);		//继续下一层 
		}	
	} 
}
void Queens()
{
	backtrack(1); //这里设定根结点为第一层,所以从1开始调用回溯算法backtrack()
}
int main()
{
	cin >> n;
	Queens();
	cout << "可行解个数:" << count;
	return 0;
}
  • 回溯法利用到了递归以及==深度优先遍历(DFS)==的思想。
发布了53 篇原创文章 · 获赞 33 · 访问量 1万+

猜你喜欢

转载自blog.csdn.net/jy_z11121/article/details/103099307