【搜索】深度優先搜索基本模型

深度優先在全排列上的應用

問題簡述

N個連續自然數的全排列。
變形:
有N張卡片(1,2,3,4,…,n),得出所有排列的可能。
排列到 N 個盒子中

想法一

在第一時間想到的肯定是枚舉法,用 for 循環來遍歷所有可能
每一個盒子都有N種可能,那麼用N層,最後判斷N個數各不重複即可。
這個時間複雜成都是O(N^9),會佔用大量的時間,而且編寫代碼也變得非常複雜。

題目解讀

  1. 有N個數字,每個盒子都有N種可能性放入
  2. 人爲規定:小的優先放入
  3. 判斷卡片是否已經被放入

想法二

我最開始還是想到了for循環
大概的想法是:

//第一個盒子N種可能
當前位置=1;
for(int i=1;i<=N;i++){
	if(沒被放入){
	 	放入當前盒子
		當前位置=2;//下一個
		//第二個盒子N種可能
		for(int i2=1;i2<=N;i2++){
			if(沒有放入){
				放入當前盒子
				當前位置=3;//下一個
				........
				//第N個盒子
				for(int iN=1;iN<=N;iN++){....結束的標誌} 
				當前位置-1;//返回 N-1層
			}
		}
		當前位置-1; //for2層結束返回for1層
	}
}
//程序結束

顯然,這並沒有減少編程的負擔,而且一旦更改N的數值,就得修改代碼…反正我不願意這麼幹哈哈。

分析這段代碼,可以發現每一層for循環內執行的任務是一樣的:找一個沒有放入的最小的數放入當前,然後跳入下一層,排完一組排列後再一層一層跳回。一組排序的結束標誌:當前位置跳到了N+1(N+1本身是不存在的)

想法三

由此想到“遞歸”編程:

  1. 重複的代碼段處理相同的任務
  2. 有結束標誌

一層一層返回也可以聯想到遞歸,遞歸函數種的 return 返回到上一次調用本函數的位置,即返回了上一層。


int box[10],book[10],N=5;
//解決第step個盒子前的組合問題
void df(int step){
	//結束標誌
	if(step == N+1){
		//打印盒子數組種的值
		for(int i=1;i<=N;i++)
			cout<<box[i];
		cout<<endl;
		return;//返回上一層
	}
	
	//遍歷N種可能
	for(int i=1;i<=N;i++){
		//判斷是否被佔用,判斷是否被標記
		if(book[i]!=1){
			//放入
			box[step] = i;
			//置標記
			book[i]=1;
			//跳入下一層
			df(step +1);
			//跳回本層
			book[i]=0;//拿出卡片,繼續循環
		}
	}
	return;//跳回上一層
}

深度優先搜索

以上思想其實就是深度有限搜索的基本模型

void dfs(int step){
	判斷邊界
	嘗試每一種可能{
		繼續下一步 ;
	}
	全部完成返回上一步
}

我個人覺得遞歸其實還是挺難的,主要在於抓住傳入的參數,重複的代碼段,和結束條件。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章