1.DFS是一种搜索算法,对每一个可能的分支路径深入到不能再深入为止,而且,每一个结点只能访问一次。
2.基本思路:从图中的某顶点a出发 - 访问顶点a - 依次从a的未被访问的邻接点出发,对图进行深度优先遍历,直至图中和a有路径相通的顶点都被访问 - 若此时图中尚有顶点未被访问,则从一个未访问的顶点出发,重新进行深度优先遍历,直到图中所有顶点均被访问过为止。
3.举个例子吧!
输出1~n的全排列(全排列函数用法)
例如1~3的全排列是123,132,213,231,312,321
大概思考一下我们会发现,每一位我们都是按照顺序进行排列的,第一位先放1,然后第二位放2,第三位放3,这样就完成了第一个排列,第二个排列我们将第二位的2换成了3,那么第三位就只剩下2,这样就完成了第二个排列,以此类推。
可以实际化一点,比如,把这个题目想象成往盒子里放球
那如何往盒子中放球呢?
for(int i = 0 ; i <= n ; ++i)
{
a[step] = i;
}
//这一步表示将第i号球放到第step个盒子里
如果球被放过,就用一个标记数组来标记哪些球被放过。
for(int i = 1;i <= n; ++i)
{
if(book[i] = 0)//book[i] = 0表示i号球没用被放过,还在手上
{
a[step] = i;//将i号球放到第step个盒子里
book[i] = 1;//将book[i]变为1,表示第i个球已经被放过
}
}
这样我们处理了第step个盒子,接下来需要处理下一个(即step + 1)个盒子,那么我们可以想到递归,即把刚刚的操作封装成一个函数,命名为dfs
代码如下:
void dfs(int step)
{
for(int i = 1; i <= n ; ++i)
{
//判断球是否被放过
if(book[i] == 0)//说明i号球没有被放过
{
a[step] = i;将第i号球放到第step个盒子里
book[i] = 1;
}
}
return;
}
把这个写成函数之后,每次调用就可以了,也就是说,处理第step+1个盒子的方法就是dfs(step + 1)
void dfs(int step)
{
for(int i = 1; i <= n ; ++i)
{
//判断球是否被放过
if(book[i] == 0)//说明i号球没有被放过
{
a[step] = i;将第i号球放到第step个盒子里
book[i] = 1;
dfs(step + 1);//函数递归调用
book[i] = 0;//这一步非常重要。必须将球收回才能进行下一步
}
}
return;
}
还有最后一个问题,如何判断一次排列结束了呢
if(step == n + 1)//如果站在第n + 1个盒子前,表示前n个盒子已经放好球了
{
for(int i = 1; i <= n ; ++i)//输出一种排列
cout << a[i]
cout << endl;
return ;
}
下面就是整体代码:
#include<iostream>
using namespace std;
int a[10];
int flag[10];
int n;
void dfs(int 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(flag[i] == 0)
{
a[step] = i;
flag[i] = 1;
dfs(step + 1);
flag[i] = 0;
}
}
return;
}
int main()
{
cin >> n;
dfs(1);
return 0;
}
dfs的基本模型:
void dfs(int step)
{
判断边界
{
继续下一步dfs(step + 1);
}
}