深度搜索

基本模型:

            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;
	}