DFS(深度优先搜索)&回溯法

         回溯法一般使用DFS实现。DFS是一种用于遍历或搜索图、树或图像等数据结构的算法,图、树不一定要存储下来,隐式处理就是回溯法。

        常见的是通过某种关系构造出搜索树,搜索树分为排列型搜索树(总节点个数一般为n!级别)和子集型搜索树(总节点个数一般为2^n级别),排列型每次枚举选哪个元素,子集型对于每个元素选或不选(结果与顺序无关)。

         DFS从起始节点开始,沿着一条路径尽可能深入地搜索,直到无法继续,然后回溯到前一个节点,继续探索其他路径,直到遍历完整个图或树。DFS使用栈或递归管理节点的遍历顺序,一般用递归。

        很多时候DFS和回溯法不必过度区分。

         模板

//求1~n的全排列
int a[N];
bool vis[N];    //vis[i]表示i是否被使用过

void dfs(int dep){
    if(dep==n+1){        //当dep=n+1时表示结束一次dfs

        for(int i=1;i<=n;i++)cout<<a[i]<<" ";
        cout<<endl;
        return;

    }
    for(int i=1;i<=n;i++){
    //若i已经被使用,跳过
        if(vis[i])continue;    
        //修改状态
        vis[i]=true;
        a[dep]=i;
        
        dfs(dep+1);
        //恢复现场
        vis[i]=false;
    }
}

班里N个小朋友,每个人都有自己最崇拜的一个小朋友(也可可以是自己)
在一个游戏中,需要小朋友坐一个圈,每个小朋友都有自己最崇拜的小朋友在他的右手边。
求满足条件的圈最大多少人?
小朋友编号为1,2,3....N。
输入描述
输入第一行,一个整数N (3<N<105)。
接下来一行N个整数,由空格分开。
输出描述
要求输出一个整数,表示满足条件的最大圈的人数。

如下图所示,崇拜关系用箭头表示,红色表示不在圈中。

#include<bits/stdc++.h>
using namespace std;
const int N=1e5+9;

int n,a[N],dfn[N],idx,mindfn;    //dfn[N]为时间戳,idx表示下标,mindfn为最小时间戳

int dfs(int x){
    dfn[x]= ++ idx;    //更新时间戳
    //若已经有时间戳,表示成环
    if(dfn[a[x]]){        
        if(dfn[a[x]]>=mindfn)return dfn[x]-dfn[a[x]];    
        return 0;
    }
    //下一层搜索
    return dfs(a[x])
}

int main()
{
    cin>>n;
    for(int i=1;i<=n;i++)cin>>a[i];
    int ans=0;
    for(int i=1;i<=n;i++){
        if(!dfn[i]){
            mindfn=idx+1;        //更新最小时间戳
            ans=max(ans,dfs(i));
        }
    }
    cout<<ans;
    return 0;
}

跑dfs求最大的环,可以用时间戳(dfn),将走过的地方标记一个时间戳(即第几步走到的)。后续搜索中,每次开始时更新最小时间戳(mindfn),如果走到已经走过的点就必须停下,然后根据时间戳的合法性来更新最大值。 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值