深度搜索
基本模型:
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;
}