1.DFS算法是一种暴力的枚举算法(在树上枚举)(枪挑一条线——DFS VS 棍扫一大片——BFS)
2.五种形式
2.1 排序树(孩子不与祖先重复)
2.2 组合树(孩子比父亲大)
2.3 子集树(左孩子0,右孩子1)
2.4 拆分树(孩子>=父亲)
2.5 搜索树(孩子和祖先不重复)
3.两个模板程序
3.1 模板一(判孩子法)(就是判断孩子是不是答案)
#include <bits/stdc++.h>
using namespace std;
#define N 1000
int ans[N];//存储答案
int vis[N];//标记变量,去重
void dfs(int k);//k表示第k层, 第k代,第k步
int main()
{
return 0;
}
void dfs(int k)//k表示第k层, 第k代,第k步
{
for(int i=1;i<=n;i++)//枚举第k代的所有孩子的线索
{
//生成孩子 (用i表示出孩子)
if()//判断孩子的合法性(符合约束条件并不重复)
{
//保存孩子
//标记孩子
if()//如果孩子是答案就输出
{
}
else//否则,继续从下一代找
{
dfs(k+1);
}
//取消标记
}
}
}
3.2 模板二(判父亲法)(就是判断父亲是不是答案)
#include <bits/stdc++.h>
using namespace std;
#define N 1000
int ans[N];//存储答案
int vis[N];//标记变量,去重
void dfs(int u);//u为父节点
int main()
{
return 0;
}
void dfs(int u)//u为父节点
{
//保存父亲
//标记父亲
if() //如果父亲是答案就输出
{
}
else//否则继续从下一代找
{
for(int i=1;i<=n;i++)
{
//生成孩子
if()//判孩子合法性(满足约束条件,不重复)
{
dfs(i);
}
}
}
//取消标记
}
4.五棵树
4.1 排序树(模板一)
#include <bits/stdc++.h>
using namespace std;
#define N 1000
int ans[N];//存储答案
int vis[N];//标记变量,去重
void dfs(int k);//k表示第k层, 第k代,第k步
int n;
int main()
{
cin>>n;
dfs(1);//从第一层开始深搜
return 0;
}
void dfs(int k)//k表示第k层, 第k代,第k步
{
for(int i=1;i<=n;i++)//枚举第k代的所有孩子的线索
{
//生成孩子 (用i表示出孩子)
if(vis[i]==0)//判断孩子的合法性(符合约束条件并不重复)
{
//保存孩子
ans[k]=i;
vis[i]=1;
//标记孩子
if(k>=n)//如果孩子是答案就输出
{
for(int j=1;j<=k;j++)
{
cout<<ans[j]<<" ";
}
cout<<endl;
}
else//否则,继续从下一代找
{
dfs(k+1);
}
//取消标记
vis[i]=0;
}
}
}
4.2 组合树(模板一)
#include <bits/stdc++.h>
using namespace std;
#define N 1000 //问题规模
int ans[N];//存储答案
int vis[N];//标记变量,去重
void dfs(int k);//k表示第k层, 第k代,第k步
int n,r;//表示从n个数中 取r个数进行组合,与顺序无关
int main()
{
cin>>n>>r;
dfs(1);//从第一层开始深搜
return 0;
}
void dfs(int k)//k表示第k层, 第k代,第k步
{
for(int i=1;i<=n;i++)//枚举第k代的所有孩子的线索
{
//生成孩子 (用i表示出孩子)
if(i>ans[k-1])//判断孩子的合法性(符合约束条件并不重复)
{
//保存孩子
ans[k]=i;
//标记孩子
if(k>=r)//如果孩子是答案就输出
{
for(int j=1;j<=k;j++)
{
cout<<ans[j]<<" ";
}
cout<<endl;
}
else//否则,继续从下一代找
{
dfs(k+1);
}
//取消标记
}
}
}
4.3 子集树(模板一)
#include <bits/stdc++.h>
using namespace std;
#define N 1000
int ans[N];//存储答案
int vis[N];//标记变量,去重
void dfs(int k);//k表示第k层, 第k代,第k步
int n;
int main()
{
cin>>n;
dfs(1);//从第一层开始深搜
return 0;
}
void dfs(int k)//k表示第k层, 第k代,第k步
{
for(int i=0;i<=1;i++)//枚举第k代的所有孩子的线索
{
//生成孩子 (用i表示出孩子)
if(1)//判断孩子的合法性(符合约束条件并不重复)
{
//保存孩子
ans[k]=i;
//标记孩子
if(k>=n)//如果孩子是答案就输出
{
for(int j=1;j<=k;j++)
{
cout<<ans[j]<<" ";
}
cout<<endl;
}
else//否则,继续从下一代找
{
dfs(k+1);
}
//取消标记
}
}
}
4.4 拆分树(模板一)
#include <bits/stdc++.h>
using namespace std;
#define N 1000
int ans[N];//存储答案
int vis[N];//标记变量,去重
void dfs(int n,int k);//k表示第k层, 第k代,第k步
int main()
{
dfs(5,1);
return 0;
}
void dfs(int n,int k)//k表示第k层, 第k代,第k步
{
for(int i=1;i<=n;i++)//枚举第k代的所有孩子的线索
{
//生成孩子 (用i表示出孩子)
if(i>=ans[k-1])//判断孩子的合法性(符合约束条件并不重复)
{
//保存孩子
ans[k]=i;
//标记孩子
n-=i;
if(n==0)//如果孩子是答案就输出
{
for(int j=1;j<=k;j++)
{
cout<<ans[j]<<" ";
}
cout<<endl;
}
else//否则,继续从下一代找
{
dfs(n,k+1);
}
//取消标记
n+=i;
}
}
}
4.5 搜索树(模板二)(因为根节点不为空)
#include <bits/stdc++.h>
using namespace std;
#define N 1000
int ans[N];//存储答案
int vis[N];//标记变量,去重
void dfs(int u,int k);//u为父节点
int n,m;// n个点,m条边
vector<int>a[N]; //动态数组
int start=0;// 起点
int target=6;//终点
int main()
{
//建图
cin>>n>>m;
for(int i=1;i<=m;i++)
{
int u,v;
cin>>u>>v;
a[u].push_back(v);
a[v].push_back(u);
}
dfs(start ,1);
return 0;
}
void dfs(int u,int k)//u为父节点
{
//保存父亲
ans[k]=u;
//标记父亲
vis[u]=1;
if(u==target) //如果父亲是答案就输出
{
for(int j=1;j<=k;j++)
{
cout<<ans[j]<<" ";
}
cout<<endl;
}
else//否则继续从下一代找
{
for(int i=0;i<a[u].size();i++)
{
//生成孩子
int v=a[u][i]; //v为u的第i个孩子
if(vis[v]==0)//判孩子合法性(满足约束条件,不重复)
{
dfs(v,k+1);
}
}
}
//取消标记
vis[u]=0;
}
/*
7 8
0 1
0 2
0 5
0 6
3 4
3 5
4 5
4 6
*/