从学完数据结构之后再没接触过算法,这次是为了备战蓝桥杯才去学算法,dfs不懂的我,陷入了巨大的沉思,只能在CSDN上摸索
但是!!!哥们我只想要dfs的模板啊,我怎么能想到你能想到的呢?慢慢悟吧,没办法了(哎)
所以我选择了从一个最简单的题入手,这个题是我自己想的哈,就是从1 2 3 4 5里面任挑3个然后输出,即高中数学的A(5/3)
首先,我们需要一个全局变量n,和一个填入了(1,2,3,4,5)的数组,当然数组也要是全局的
还有一个全局的vis数组,用来标记是否访问过这个元素(这个下面会提到)
b数组用来存储答案,cns数组用来算总的结果数,不出意外的话:cns=6x5x4=60
int n,a[100],vis[100],b[100],cns;
然后就是简单的输入,这里不多赘述
int main()
{
cin>>n;
for(int i=1;i<=n;i++) //这里建议大家从1开始存哈,后面的step会方便一点
{
cin>>a[i];
}
dfs(1); //这个先别管,先看下面
cout<
①定义一个 step 变量,用来表示我们现在选的是第几个数 ( 比如dfs(1),那么代表着我现在正在选第1个数,还不知道花落谁家 )
void dfs(int step) //模板,可能不同的题会需要多个参数
②接着存数进b数组,我们到时候要输出,下面的这几行代码都是模板,请牢牢记住
for(int i=1;i<=n;i++) //注释一如下
{
if(vis[i]) // 模板:判断vis数组中这个数有没有被选过,如果选过,就continue
{
continue;
}
b[step]=a[i]; // 模板:存入最终要存输出的答案的数组
vis[i]=1; // 已经选中它啦,所以要把vis数组的第i个置为1,表示我已经选过了
dfs(step+1); //选下一个啦
vis[i]=0; // 这里也是我当初学的时候很不理解的一个点,但是我后来悟道了,注释二
}
注释一:状态:你的有关step的最终要存输出的答案的数组里最终要存的是什么?如果是(1,2,3,4,5)的a数组任选一个,那么就是要选择关于a数组的循环,这里选择从(1,n)循环遍历a数组
注释二:这里为什么要重置呢?建议和下面的一起看哈!如果从程序的角度来说:
(1)我们先选了1,此时有关1的还有一个最外层的循环啊,就是(1,5)的这个循环
(2)然后深搜dfs(2),此时注意再次进了上面这个循环,因为vis【1】=1,所以不选,继续循环,i=2,vis【2】=0,所以可选,选中2
(3)同理继续深搜,vis【1】=vis【2】=1,vis【3】=0,选中3,注意:此时我们已经选了3个数了
(4)继续深搜:此时为dfs(4),选了3个数了,所以我们需要输出并且返回上一个选中3的循环,那么下一步就应该是vis【3】置为0
(5)这个时候你就会想啦,为啥要把它置为0呢?这是因为:3已经遍历过了,按道理来说,下一个是(1,2,4),但是你已经选中了(1,2,3)啦,你不丢掉一个,怎么选下一个呢,那么此时丢掉3,即vis【3】置为0,此时我们才2个数,还是可以寻找第3个数的
(6)那么这时,在我们最深层的循环中,会接着跳过3去遍历4
《可以画一个图帮助理解一下》
③什么时候return,输出呢,当然是选了3个数的时候啦,即step==4
if(step==4) //模板:填写输出阈值
{
for(int i=1;i<4;i++) //输出
{
printf("%d ",b[i]);
}
cns++; //看题目要求,可加可不加,如果题目需要先输出总数,再输出各种情况,那么就需要开个二维数组把情况都存起来,暂时就不能输出
printf("\n");
return ;
}
总代码如下
#include
#include
#include
大家可以先别看,先自己试着写一下,我们难度慢慢递进
你可以发现,完完全全按模板来写就行
#include
#include
#include
大家可以先别看,先自己试着写一下,注意之前注释一中提到的状态,我们的最终数组里究竟要存的是什么?
#include
#include
#include
区别在于:记录遍历的数组vis增加,从1个变成了4个
#include
#include
#include
“算法虐我千百遍,我待算法如初恋”,加油,希望未来我们顶峰相见!!!收藏一下吧嘿嘿