前言
- DFS= 递归
- 适于寻找一个最优解
- 常用技巧: 减枝
判父亲法
void dfs(int u)
{
//保存父亲
//标记父亲
if()//如果父亲是答案就输出(判父亲法)
{
//输出答案
}
else//如果父亲不是答案,继续从下一代找
{
for(int i=1;i<=N;i++)//枚举第u代的所有孩子的i
{
//生成孩子
if()//判断孩子的合法性
{
dfs(i);//递归搜索u的孩子
}
}
}
//取消标记
}
搜索树
vector<int> a[N];
void dfs(int u, int k)
{
ans[k] = u;
vis[u] = 1; //标记父亲
if (u == ans) //符合
{
for (int i = 1; i <= k; i++)
cout << ans[i] << " ";
cout << endl;//处理答案
}
else
for (int i = 0; i < a[u].size(); i++)//生成孩子线索
{
int v = a[u][i]; //生成孩子
if (vis[v] == 0)
dfs(v, k + 1); //下一个
}
vis[u] = 0; //取消标记
}
int main()
{
for (int i = 1; i <= n; 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 k)
{
for(int i=1;i<=N;i++)//枚举第k代的所有孩子的线索
{
//生成孩子(用i表示出孩子)
if()//判孩子的合法性(符合约束条件并且不重复)
{
//保存孩子
//标记孩子
if()//如果孩子是答案就输出
{
}
else//如果孩子不是答案,继续从下一代找
{
dfs(k+1);
}
//取消标记
}
}
}
子集树
void dfs(int k)
{
for(int i=0; i<=1; i++)
{
ans[k]=i;
if(k>=n)
{
for(int j=1; j<=k; j++)
cout<<ans[j]<<" ";
cout<<endl;
}
else
dfs(k+1);
}
}
int main()
{
cin>>n;
dfs(1);
return 0;
}
拆分树
void dfs(int s,int k)
{
for(int i=1; i<=s; i++)
{
if(i>=ans[k-1])
{
ans[k]=i;
s-=i;
if(s==0)
{
for(int j=1; j<=k; j++)
cout<<ans[j]<<" ";
cout<<endl;
}
else
dfs(s,k+1);
s+=i;
}
}
}
int main()
{
cin>>n;
ans[0]=1;
dfs(n,1);
return 0;
}
组合树
void dfs(int k)
{
for(int i=1;i<=n;i++)
{
if(i>ans[k-1])
{
ans[k]=i;
if(k>=m)
{
for(int j=1;j<=k;j++)
cout<<ans[j]<<" ";
cout<<endl;
}
else
dfs(k+1);
}
}
}
int main()
{
cin>>n>>m;
dfs(1);
return 0;
}
排序树
void dfs(int k)
{
for(int i=1;i<=n;i++)
{
if(vis[i]==0)
{
ans[k]=i;
vis[i]=1;
if(k>=n)
{
for(int j=1;j<=n;j++)
cout<<ans[j]<<" ";
cout<<endl;
}
else
dfs(k+1);
vis[i]=0;
}
}
}
int main()
{
cin>>n;
dfs(1);
return 0;
}
减枝
- 1.不合法: 返回
- 2.花费超过从前查到的最优解: 退出
- 3.冗余: 退出
- 4.记忆化