1. 程式人生 > >遞迴——以全排列和n皇后問題舉例

遞迴——以全排列和n皇后問題舉例

筆記來自【晴神寶典】

一、遞迴

遞迴 就在於反覆呼叫自身函式,但是每次都把問題範圍縮小,直到範圍可以縮小到可以直接得到邊界資料的結果,然後在返回路上求出對應的解。以上可看出,遞迴很適合用來實現分治思想

遞迴兩個很重要的組成組成:

1、遞迴邊界(出口);

2、遞迴式。

 

二、全排列 (Full Permutation)

【可畫圖,便於理解】

#include <cstdio>
const int maxn=100;
//P為當前排列,hashTable記錄整數x是否已經在P中 
int n, P[maxn], hashTable[maxn]={false};
//當前處理排列的第index號位
void generateP(int index){
	if(index==n+1){
		for(int i=1; i<=n; i++){
			printf("%d", p[i]);
		}
		printf("\n");
		return ;
	}
	for(int x=1; x<=n; x++){
		if(hashTable[x]==false){
			P[index]=x;
			hashTable[x]=true;
			generateP(index+1);
			hashTable[x]=false; //已處理完p[index]為x的子序列問題,還原狀態 
		} 
	}
} 
int main() {
	n=3; 
	generateP(1);
	return 0;
}

二、n皇后問題

n皇后問題 是指在一個 n*n 的國際象棋棋盤上放置n個皇后,使得這n個皇后兩兩均不在同一行、同一列、同一條對角線上,求合法的方案數。

1、暴力法(列舉所有情況)

#include <cstdio>
#include<math.h>
const int maxn=100;
int n, P[maxn], hashTable[maxn]={false};
int count=0;
void generateP(int index){
	if(index==n+1){
		bool 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; //不合法 
				}
			}
		}
		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; //已處理完p[index]為x的子序列問題,還原狀態 
		} 
	}
} 
int main() {
	n=8; 
	generateP(1);
	printf("%d", count); //92
	return 0;
}

2、回溯法

到達遞迴邊界前的某層時,由於一些事實導致已經不需要再往下遞迴了,就直接返回上一層。

#include <cstdio>
#include<math.h>
const int maxn=100;
int n, P[maxn], hashTable[maxn]={false};
int count=0;
void generateP(int index){
	if(index==n+1){
		count++; //能到遞迴邊界一定是合法的
		return ; 
	}
	for(int x=1; x<=n; x++){
		if(hashTable[x]==false){//第x行還沒有皇后 
			bool flag=true;
			for(int pre=1; pre<index; pre++){//遍歷之前的皇后 
				if(abs(index-pre)==abs(x-P[pre])){//是否與之前的皇后對角線衝突 
					flag=false;
					break; 
				}
			}
			if(flag==true){
				P[index]=x;
				hashTable[x]=true;
				generateP(index+1);
				hashTable[x]=false; //已處理完p[index]為x的子序列問題,還原狀態 
			}
		} 
	}
} 
int main() {
	n=8; 
	generateP(1);
	printf("%d", count); //92
	return 0;
}