<strong><span style="font-size:18px;">题目:输入一个数N,输出1~N的全排列。</span></strong>
本例子用 向 标有1、2、3、4...标号的箱子派发纸牌(1、2、3....)的方式来讲解深度优先搜索,等同于数学里面的全排列的知识
理解深度优先搜索的关键是解决“当下该如何做”或“下一步如何做”。下面:
#include <iostream>
using namespace std;
int a[10],book[10],n;
//book[]是标志性数组,当book[i]=0,表明该牌i还没使用,否则为已使用
//数组a[]是表示盒子
void dfs(int step)//用step表示当前所在的箱子前面
{
int i;
if(step == n+1) //表明前n个箱子已经放好牌
{
for(i =1 ;i <=n; i++)
cout<<a[i]; //输出一种排序
cout<<"\n";
return;
}
for(i = 1; i<= n;i++)
{
if(book[i]==0)
{
//开始尝试使用牌i
a[step]=i; //将I号牌放入第step个盒子中
book[i]=1; //将book[i]设为1,表示牌i不在手上了
dfs(step+1); //函数递归
book[i]=0; //当执行到这里的时候,所以必须将牌回收,进行下一轮
}
}
return ; //遍历结束
}
int main()
{
cin>>n;
dfs(1);
getchar();
getchar();
return 0;
}
这里的dfs(step)函数就是解决当前在第step个盒子的时候,下一步该怎么办。通常的方法就是把每一种可能都去尝试一遍(一般使用for循环来遍历)。当前这一步解决后就是进入下一步dfs(step+1).
深度优先搜索的基本模型如下:
void dfs(int step)
{
判断边界
尝试每一种可能 for(;;)
{
继续下一步dfs(step+1)
}
return;
}
补充:下面对回收牌那里说明一下(改写了一下上面的代码)
for(i = 1; i<= n;i++)//每一次for循环,step都为1开始
{
if(book[i]==0)
{
//开始尝试使用牌i
a[step]=i; //将I号牌放入第step个盒子中
cout<<" @"<<step<<"@ ";
book[i]=1; //将book[i]设为1,表示牌i不在手上了
dfs(step+1); //函数递归,最后有几个递归就有几个return,然后执行下面的代码
cout<<"调用完dfs()后step+1= "<<step+1<<" ";
book[i]=0; //当执行到这里的时候,已经完成了一次完整的尝试,所以必须将牌回收,进行下一轮
cout<<"#回收"<<i<<" ";
}
}
通过细心的看下面的运行结果应该可以较清晰的看出回收牌是怎样一个流程
下面再补充一个案例:1~9的数字,形如abc+def=ghi 的等式 有多少个?
#include<iostream>
using namespace std;
int a[10]; //位置数组,看成是10个箱子即可
int book[10]; //标识数组,0 表示还没使用,1 表示已使用
int total; //计数
void dfs(int step) //step表示现在站在第几个箱子钱
{
int i;
if(step == 10)
{
//判断是否满足等式abc*def=ghi
if(a[1]*100+a[2]*10+a[3]+a[4]*100+a[5]*10+a[6]
== a[7]*100+a[8]*10+a[9])
{
total++;
cout<<a[1]<<a[2]<<a[3]<<"+"<<a[4]<<a[5]<<a[6]<<"="<<a[7]<<a[8]<<a[9];
cout<<endl;
}
return;
}
for(i=1;i<=9;i++)
{
//判断牌是否还在手上
if(book[i] == 0)
{
//开始尝试使用牌
a[step] = i; //把牌i放入第step个盒子中
book[i] = 1; //表示牌i已经不再手上
dfs(step+1); //通过递归,向下一个箱子放置牌
book[i] = 0; //收回牌,有几次递归就有几次收回牌
}
}
return ;
}
int main()
{
dfs(1);
cout<<total/2;
getchar();
getchar();
return 0;
}
ps:系列算法总结文章根据《啊哈!算法》整理。