回溯法一般使用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),如果走到已经走过的点就必须停下,然后根据时间戳的合法性来更新最大值。

1099

被折叠的 条评论
为什么被折叠?



