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

深度优先在全排列上的应用

问题简述

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){
	判断边界
	尝试每一种可能{
		继续下一步 ;
	}
	全部完成返回上一步
}

我个人觉得递归其实还是挺难的,主要在于抓住传入的参数,重复的代码段,和结束条件。

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