深度搜索

 深度搜索

基本模型

            void dfs(int step){
    判断边界
    尝试每一种可能for(i=1;i<=n;i++){
      继续下一步dfs(step+1);
    }
     返回;
  }

实质:从问题的某一种可能性出发,找出从这种情况出发的、可以满足条件的所有的解;

          尽可能的“深”的探索某一分支,如假设从a情况出发,找到以a为起点(前提)的可满足的解的所有情况

         然后再回溯(返回)a的上一个节点,重复进行这种类似的寻找。

        具体例子:

                放扑克牌问题,有编号1-9的扑克牌和盒子,求所有可能的排放组合。【啊哈算法第四章】

先假设有三张扑克牌,三个盒子,约定按照顺序存放,先1号盒子对应1号扑克牌,2号盒子对应2号扑克牌,3号盒子对应三号扑克牌

之后,来到第四个盒子面前,因为只有三个盒子三个纸牌,所以此时为满足条件的一种排列,之后回溯,尝试另外的可能性,先把3号扑克牌从

3号盒子中取出,看还没有其他的扑克牌可以存放,没有,回溯到2号,将2号扑克牌从2号盒子中取出,此时我们手里已经有2、3号两扑克牌,

由于先前2号盒子里已经放过2号扑克牌了,故此时2号盒子中存放3号扑克牌,之后再在此种情况下出发,寻找3号盒子中扑克牌可能的放法。

之后再回溯2号,1号,以此类推,...

1.       首先放扑克牌,利用for循环

变量step表示当前在第step个盒子面前

for(int i=1;i<=n;i++){

a[step]=1;//将i号扑克牌放到第step个盒子中去

}

2.在某一位置放扑克牌的前提是不能放置和上一步同样的扑克牌,设一个数组book[i],book[i]=1,表示当前位置i号扑克牌已经被使用过了,不能再被

使用。

for(i=1;i<=n;i++){

if(book[i]==0){

a[step]=i;

book[i]=1;

    }

3.上两步已经处理好第step个盒子了,接下来处理第step+1个盒子方法是递归

void dfs(int step){

for(i=1;i<=n;i++){

//判断扑克牌i是否在手上

if(book[i]==0){

a[step]=i;//将编号为i的扑克牌放到第step个盒子中

book[i]=1;//将book[i]设为1,表示该i号扑克牌已经在手上了

     }

}

//处理好step个盒子后开始处理第step+1个盒子,方法dfs(step+1)

void dfs(int step){


//求一个数的全排列问题
/*
输出一个数n,输出1-n的全排列
思想:有编号1-3的扑克牌,和编号为1-3的盒子
求不同的放法?
【思路】
1.判断边界,因为要放置n的盒子,所以,当当前盒子为第n+1个盒子时,说明前n个盒子已经放置好了。
此时只需要输出即可
2.循环判断当前纸牌是否被放入,未放入,放入,并标志为已放入状态,已放入的,循环尝试。
3.使用迭代,进行下一次判断。
*/
#include
   
   
    
    
int a[10], book[10], n;

void dfs(int step){
	int i;
	//--------------------判断边界------------,如果站在第n+1个盒子面前,则表示前n个盒子已经放好
	if (step == n + 1){
		for (i = 1; i <= n; i++)
			printf("%d",a[i]);
		printf("\n");
		return;
	}
	//-------------------end-----------------
	//-------------------尝试每一种情况----------------------
	for (i = 1; i <= n; i++){
		//判断扑克牌i是否在手上
		if (book[i] == 0){//book[i]等于0表示i号牌在手上
			a[step] = i;//将i号扑克牌放到第step盒子中
			book[i] = 1;//将book[i]设为1,表示i号扑克牌在手上
			//第step个盒子已经放好扑克牌,接下来需要走到下一个盒子中
			dfs(step + 1);//函数递归,实现
			book[i] = 0;//将刚才尝试的扑克牌收回,进行下一次尝试
		}
	}
		return;
	}
	int main(){
		scanf_s("%d",&n);//输入时要注意n为1-9的整数
		dfs(1);
		getchar(); getchar();
		return 0;
	}

   
   

     for(i=1;i<=n;i++){

        a[step]=i;     //将i号扑克牌放到第step个盒子中

        book[i]=1;//将book[i]设为1,表示i扑克牌已经不再手中

        dfs(step+1);//通过函数的递归调用来实现

        book[i]=0;//将刚才尝试的扑克牌收回,才能进行下一步的尝试

   }

}

4.搜索结束的条件,当step==n+1时,表明前n个扑克牌已经放好了,此时打印就可以了

void dfs(int step){

if(step==n+1){

for(i=1;i<=n;i++)   printf("%d",a[i]);

printf("\n");

return ;//返回之前的一步,(最近一次调用dfs函数的地方)

}

for(i=1;i<=n;i++){

if(book[i]==0){//判断扑克牌i是否在手上

a[step]=i;//将i号扑克牌放入到第step个盒子中

book[i]=1;//i号扑克牌已经不再手上

dfs(step+1);

book[i]=0;

   }

}


//---------------------------------------------------------------------------------------完整代码如下------------------------------------------------------------------------------------------------------

//求一个数的全排列问题
/*
输出一个数n,输出1-n的全排列
思想:有编号1-3的扑克牌,和编号为1-3的盒子
求不同的放法?
【思路】
1.判断边界,因为要放置n的盒子,所以,当当前盒子为第n+1个盒子时,说明前n个盒子已经放置好了。
此时只需要输出即可
2.循环判断当前纸牌是否被放入,未放入,放入,并标志为已放入状态,已放入的,循环尝试。
3.使用迭代,进行下一次判断。
*/
#include
    
    
     
     
int a[10], book[10], n;

void dfs(int step){
	int i;
	//--------------------判断边界------------,如果站在第n+1个盒子面前,则表示前n个盒子已经放好
	if (step == n + 1){
		for (i = 1; i <= n; i++)
			printf("%d",a[i]);
		printf("\n");
		return;
	}
	//-------------------end-----------------
	//-------------------尝试每一种情况----------------------
	for (i = 1; i <= n; i++){
		//判断扑克牌i是否在手上
		if (book[i] == 0){//book[i]等于0表示i号牌在手上
			a[step] = i;//将i号扑克牌放到第step盒子中
			book[i] = 1;//将book[i]设为1,表示i号扑克牌在手上
			//第step个盒子已经放好扑克牌,接下来需要走到下一个盒子中
			dfs(step + 1);//函数递归,实现
			book[i] = 0;//将刚才尝试的扑克牌收回,进行下一次尝试
		}
	}
		return;
	}
	int main(){
		scanf_s("%d",&n);//输入时要注意n为1-9的整数
		dfs(1);
		getchar(); getchar();
		return 0;
	}

    
    











  • 1
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

罚站的孩子

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值