算法笔记_全排列与N皇后问题

说明:这里的全排列是按字典序的.

以下给出从1到3的全排列代码:

#include<iostream>
#include<stdlib.h>
using namespace std;
const int maxn = 11;
//P为当前排列,hashTable记录整数x是否已经在P中
int p[maxn];// 必须申明为全局 
bool hashTable[maxn] = { false };// 必须申明为全局 
int n;// 必须申明为全局 
//当前处理排列的第index号位
void generateP(int index)
{
	if (index == n + 1)//递归边界:当index递归到n+1时,说明index已经从1至n递归完毕了
	{
		for (int i = 1; i <= n; i++)
		{
			cout << p[i];///输出当前排列
		}
		cout << endl;
		return;
	}
	for (int x = 1; x <= n; x++)//枚举1至n,试图将x填入p[index]
	{
		if (hashTable[x] == false)//如果x不在p[0]至p[index-1]中,则
		{
			p[index] = x;//令p的第index位为x,即把x加入当前排列
			hashTable[x] = true;//记x已在p中
			generateP(index + 1);//处理排列的第index+1号位
			hashTable[x] = false;//已处理完p[index]为x的子问题,还原状态
		}
	}
}
int main(void)
{
	n = 3;//欲输出1至3的全排列
	generateP(1);//从p[1]开始填
	system("pause");
	return 0;
}

注:其中generateP函数的代码十分重要,切记.

以下来讨论N皇后问题,其实N皇后问题输出值是解决方案个数,其实质就是全排列的应用.

1)暴力法(一般把不使用优化算法,直接用朴素算法来解决问题的做法称暴力法)

//第i列皇后的行号为P[i],第j列皇后行号为P[j].
int count = 0;
void generateP(int index)
{
	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
				{
					flag = false;
				}
			}
		}
		if (flag) count++;//合法则加一
		return;
	}
	for (int x = 1; x <= n; x++)
	{
		if (hashTable[x] == false)
		{
			P[index] = x;
			hashTable[x] = true;
			generateP(index + 1);
			hashTable[x] = false;
		}
	}
}

2)回溯法(一般来说,如果在到达递归边界前的某层,由于一些事实导致已经不需要往任何一个子问题递归,就可以直接返回上一层)

void generateP(int index)
{
	if (index == n + 1)//递归边界,生成一个合法方案
	{
		count++;//能达到这一定合法
		return;
	}
	for (int x = 1; x <= n; x++)//第n行
	{
		if (hashTable[x] == false)//第n行还没有皇后
		{
			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;//与之前的皇后在一条对角线冲突
					break;
				}
			}
			if (flag)//如果可以把皇后放在第x行
			{
				P[index] = x;//令第index列皇后的行号为x
				hashTable[x] = true;//第x行已被占用
				generateP(index + 1);//递归处理第index+1行皇后
				hashTable[x] = false;//递归完毕,还原第x行为未占用
			}
		}
	}
}

1)暴力法(一般把不使用优化算法,直接用朴素算法来解决问题的做法称暴力法)

猜你喜欢

转载自blog.csdn.net/qq_41938259/article/details/81006365