acwing 递归实现组合型枚举 dfs第二讲 (第四次讲解)

                                                         前言(给看我博客的新友用来了解我的内容风格用的)

经历了三次我给大家讲解acwing算法基础课,相信大家对我的讲课风格有所了解。我是想通过代数加动画的方式讲解代码让大家真正了解代码的来龙去脉,说实话y总的代码比一些信奥竞赛上的代码容易理解多了,但是可能我这个人比较较真,而且也没啥基础,所以开始学起来的时候还是很迷茫的,希望我能把我的想法跟大家一起交流一下,一起进步。

                                                       正文(DFS实现 递归实现组合型枚举)

上文跟大家讲dfs的原理了,废话少说上代码,秉承上次的解题动画习惯,还是用代数法给大家去展示一下具体代码是如何一步一步走的,以及如何实现的递归(还是说了不少废话不好意思嘿嘿)

acwing 递归实现组合型枚举 dfs第二讲 (第四次讲解)_第1张图片动画献上(这里的圈1圈2就是步骤)

上代码

#include 
#include 
#include 
#include 

using namespace std;

const int N = 30;

int n, m;
int way[N];

void dfs(int u, int start)
{
    if (u + n - start < m) return;  // 剪枝
    if (u == m + 1)
    {
        for (int i = 1; i <= m; i ++ ) printf("%d ", way[i]);
        puts("");
        return;
    }

    for (int i = start; i <= n; i ++ )
    {
        way[u] = i;
        dfs(u + 1, i + 1);
        way[u] = 0; // 恢复现场
    }
}

int main()
{
    scanf("%d%d", &n, &m);

    dfs(1, 1);

    return 0;
}

其实还是跟上次一样恢复现场不影响ac,实在理解不了的把这句话就去掉,包括剪枝也不影响ac结果,但是!!!!我要给大家讲一下剪枝怎么来的,因为不剪枝的话大概277ms但是剪枝的话大概98ms,差距不小。

!!我写代数法先忽略恢复现场和剪枝法,后面我写几个例子去证明和讲解剪枝,要不然太多了每次都剪枝判断。

!!!!!注意这不是代码这是代数法的笔记,上次有个佬说我那样写太难受了,所以我把笔记写成代码的形式大家看着舒服一点点
算法里面的代码我把它分成两个部分
后面用 s 代替start
第一部分(后面我用它的时候也会用01代替)我愿称它为输出环节
    if (u + n - start < m) return;  // 剪枝
    if (u == m + 1)
    {
        for (int i = 1; i <= m; i ++ ) printf("%d ", way[i]);
        puts("");
        return;
    }
第二部分(后面我用它的时候会用02代替)我愿称它为递归环节
  for (int i = start; i <= n; i ++ )
    {
        way[u] = i;
        dfs(u + 1, i + 1);
        way[u] = 0; // 恢复现场
    }

eg:求从5个整数求三个数输出所有的可能那么 n=5 m=3
从int main()后面看他是从dfs(1,1)开始递归
dfs(1,1)进入01没反应然后再进入02
i=s=1 ,1<5;
way[1]=1
dfs(2,2);
dfs(2,2)进入01没反应然后再进入02
i=s=2;2<5
way[2]=2
dfs(3,3);
dfs(3,3)进入01没反应然后再进入02
i=s=3;3<5
way[3]=3
dfs(4,4);
dfs(4,4)进入01直接输出1 2 3 然后return
!!!!!!!!!  i=s=4<5(这是回溯u=3 dfs(3,))
way[3]=4
dfs(4,5);
dfs(4,5)进入01直接输出1 2 4 然后return
i=s=5=5 回溯u=3
way[3]=5
dfs(4,6)
dfs(4,6)进入01直接输出1 2 5 然后return
i=s=6>5(已经走完了dfs(3,3))
!!!!!回溯dfs(2,2)
此时i=2走完i++之后是i=s=3<5
way[2]=3
dfs(3,4);
dfs(3,4)进入01没反应然后再进入02
i=s=4<5
way[3]=4
dfs(4,5)(!!!!注意这里虽然跟第38行穿的值一模一样但是数组存的数不一样了所以输出不一样了)
dfs(4,5)进入01直接输出1 3 4 然后return
基本上剩下的大家就可以找猫画虎写出来了对照我那个动画图片
!!!!!!!!!!!!解释一下这里不是播主懒不想给大家继续写了,只是我感觉:纸上得来终觉浅 绝知此事要躬行。看博主写当然很爽但是博主当时写的时候感觉是一遍写一遍思考所以收获比较大
大家要是完整写下来估计就理解了,所以大家自己试试看,我后面看反馈然后有问题,哪怕一人提问博主都老老实实写一遍全部过程好吧
!!!!!!!讲俩个剪枝的例子证明一下
代数传值dfs(4,5)应该是输出1 3 4此时状态 u=4 start=5 u+n-start=4!<3 所以不用剪枝
比如递归到1 5 x 大家都知道x是没有的因为不能再递归了最大就是 1 4 5 ,此时 u=3 start=6 u+n-start=3+5-6=2<3 cut

今天就先讲到这里明天讲全排列给大家整点简单acm模板尽情期待。

你可能感兴趣的:(深度优先,算法)