啊哈算法第四章 万能的搜索

从这一章开始就真的步入对我而言全新的算法世界了(因为排序、枚举在上学期还是接触过的,而栈、队列在这学期我看的C++Primer和老师教的Java课里也有所涉及)

一、深度优先搜索Depth First Search)

首先作者用上章遗留的全排列问题作为引例为我们介绍了DFS是啥东西。

题目1:输入一个数n 请输出1~n的全排列。

当然我们可以用上一章的枚举来做,并且用一个book[10]的数组还能减少一些麻烦,但其实还是很麻烦……而用dfs则简单得多。上代码。

#include<iostream>
using namespace std;
int a[10], book[10], n;
void dfs(int step)   //现在站在第step个盒子前。   
{	
	if (step == n + 1)
	{
		for (int i = 1; i <= n; ++i)
			cout << a[i];
		cout << endl;
		return;
	}
	for (int i = 1; i <= n; ++i)
	{
		if (book[i]==0)    //牌在手上 
		{
			a[step] = i;   //放入盒子中
			book[i] = 1;     //牌不在手上了
			dfs(step + 1);     //走向下一个盒子
			book[i] = 0;     //把刚才尝试的牌都收回来,再进行下一次的排列尝试
		}
	}
	return;
}
int main()
{
	cin >> n;
	dfs(1);
	system("pause");
}

其实主要要注意的是其中的递归问题

分析

首先我们站在第一个盒子(作者将每一个数比作一个对应的盒子)面前,所以main函数中是dfs(1),在dfs函数中,我们将1到n每一个数都进行尝试,如果这个牌仍在手中,则放入盒子里,然后走向下一个盒子(dfs(step+1)),直到走到了n+1个盒子,当然这个盒子不存在,也就是说我们已经走到了尽头,便将排好的一个排列输出,return。作者说必须马上return,但其实并不需要,不会陷入死循环,因为在下方遍历1~n时并没有牌在手中,所以并不会继续dfs(step+1) 而是仍会执行最下面的return语句。(但是,最好还是写上那条return语句,因为可以不用再去遍历循环以提高效率,并且,if(step==n+1)这一语句块是递归的结束条件,一般来说在结束条件都要return以避免死循环的 所以养成好习惯不是坏事~)

当执行完一次排列后(也就是一次step到n+1后),return,则返回到上一次调用dfs的地方,也就是循环中的dfs(step+1)这一语句,其实这就是递归啦,那么下一句就是book[i]=0; 即收回刚才放入盒子中的牌,然后一直递归, 一直收牌,直到可以有不同排列时停止,此时便进行下一种排列。(这里最好自己脑子里想一遍全过程,下一段落我也给出了过程帮助理解)这也就是为什么作者说book[i]=0;这一语句十分重要的原因,如果不收回牌,则无法进行下一次排列。  最后,最后一条语句return也不要忘了。。

嗯,这里还是给一小部分过程帮助理解吧。比如要给出1到3的全排列。 最开始,我们是站在第一个盒子面前,从1~n遍历,因为有1,所以放进盒子中,手里也就没有1了,然后走向下一个盒子,从1~n遍历,没有1,但是有2,将2放入盒子中,手中没有2了……最后走到第四个盒子时,刚好放入了123,输出123,返回到上一次调用dfs函数的地方,即在第三个盒子处,我们将盒子三里的牌收回来(即3),因为在这时循环i==3 所以++i后循环结束,return 又到了上一个调用dfs函数的地方,则是在第二个盒子处,收回在第二个盒子里的牌(即2),此时循环

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值