1.DFS算法是暴力算法,是枚举算法的另外一种形式(树上枚举)
1.1 枪挑一条线(DFS)
1.2 棍扫一大片(BFS)
2. 五种形式
2.1 排序树(孩子和祖先不重复)
2.2 组合树(孩子要比父亲大)
2.3 子集树(左孩子为0,右孩子为1,太极生两仪,两仪生四象,四象生八卦)
2.4 拆分树(孩子大于等于父亲)
2.5 搜索树(孩子和祖先不能重复)
3. 两个模板+5棵树形式
3.1 模板1 (判孩子法)
#include<bits/stdc++.h>
using namespace std;
#define N 1000 //问题的规模
int ans[N];
int vis[N];
void dfs(int k);
int main()
{
return 0;
}
void dfs(int k) //第k代,第k层,第k步。
{
for(int i=1;i<=n;i++) //枚举第K代孩子的所有线索
{
//生成孩子(用i表示出孩子)
if() //判断孩子的合法性(符合约束条件且不重复)
{
//保存孩子
//标记孩子
if() //如果孩子是答案
{
}
else//继续从下一代找
{
dfs(k+1);
}
//取消标记
}
}
}
3.2 模板2 (判父亲法)
#include<bits/stdc++.h>
using namespace std;
#define N 1000 //问题的规模
int ans[N];
int vis[N];
void dfs(int k);
int main()
{
return 0;
}
void dfs(int u) //u为父节点
{
//保存父亲
//标记父亲
if() //如果父亲是答案就输出
{
}
else //父亲不是答案,继续从下一代找
{
for(int i=1;i<n;i++)
{
//生成孩子
if() //判断孩子的合法行(符合约束条件并不重复)
{
dfs(i);
}
}
}
// 取消标记(与标记父亲对应)
}
3.3 排序树(模板1)
#include<bits/stdc++.h>
using namespace std;
#define N 1000 //问题的规模
int ans[N];
int vis[N];
void dfs(int k);
int n;
int main()
{
cin>>n;
dfs(1); //从第一代深搜
return 0;
}
void dfs(int 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;
}
}
}
3.4 组合树(模板1)
#include<bits/stdc++.h>
using namespace std;
#define N 1000 //问题的规模
int ans[N];
int vis[N];
void dfs(int k);
int n,r; //表示从n个数中取r个进行组合,与顺序无关
int main()
{
cin>>n>>r;
dfs(1); //从第1层开始深搜
return 0;
}
void dfs(int 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<<' ';
}
cout<<endl;
}
else//继续从下一代找
{
dfs(k+1);
}
//取消标记
}
}
}
3.5 子集树(模板1)
#include<bits/stdc++.h>
using namespace std;
#define N 1000 //问题的规模
int ans[N];
int vis[N];
void dfs(int k);
int main()
{
dfs(1);
return 0;
}
void dfs(int k) //第k代,第k层,第k步。
{
for(int i=0;i<=1;i++) //枚举第K代孩子的所有线索
{
//生成孩子(用i表示出孩子)
if(1) //判断孩子的合法性(符合约束条件且不重复)
{
//保存孩子
ans[k]=i;
//标记孩子
if(k>=3) //如果孩子是答案
{
for(int j=1;j<=k;j++)
{
cout<<ans[j];
}
cout<<endl;
}
else//继续从下一代找
{
dfs(k+1);
}
//取消标记
}
}
}
3.6 拆分树(模板1)
#include<bits/stdc++.h>
using namespace std;
#define N 1000 //问题的规模
int ans[N];
int vis[N];
void dfs(int n,int k);
int main()
{
dfs(20,1);
return 0;
}
void dfs(int n,int 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;//取消标记
}
}
}
3.7 搜索树(模板2)
#include<bits/stdc++.h>
using namespace std;
#define N 1000 //问题的规模
int ans[N];
int vis[N];
void dfs(int u,int k);
int m,n; //n个点m条边
vector<int> a[N]; //使用动态数组存储
int start=0,target=2;
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;
}
/*
5 7
0 1
0 3
0 4
1 2
1 4
2 3
3 4
*/