1. 程式人生 > >演算法筆記_全排列與N皇后問題

演算法筆記_全排列與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)暴力法(一般把不使用優化演算法,直接用樸素演算法來解決問題的做法稱暴力法)