树递归 - 如何在深度优先搜索中包含条件?
Posted
技术标签:
【中文标题】树递归 - 如何在深度优先搜索中包含条件?【英文标题】:Tree recursion - how to include conditions in depth-first search? 【发布时间】:2022-01-11 03:30:33 【问题描述】:我有一棵树(非二进制、不平衡、无循环),所有节点都有标志(绿色=活动,红色=不活动)。我从根节点开始,我必须找到所有节点都处于活动状态的完整路径(从根到叶)。 (找到至少一条路径就可以了。)因此,我需要路径,而不仅仅是信息(如果有的话)。
我正在考虑使用深度优先搜索,但我不知道如何包含按活动/非活动进行的过滤。有什么想法吗?
【问题讨论】:
【参考方案1】:假设
A 1
/ \ / \
B C -- G 2 3 -- 7
/ \ \ \ <=> / \ \ \
D E F J 4 5 6 10
/ \ \ / \ \
H I K 8 9 11
因此,我可以使用算法深度优先搜索为您的问题提供解决方案。
/*
A - 1,
B - 2,
C - 3,
D - 4,
E - 5,
F - 6,
G - 7,
H - 8,
I - 9,
J - 10,
K - 11.
*/
#include <iostream>
#include <vector>
#include <string>
#include <algorithm>
using namespace std;
const int maximumSize=20;
int vertices, edges;
vector<int> visited0(maximumSize, 0);
vector<int> visited1(maximumSize, 0);
vector<int> graph[maximumSize];
vector<int> distances(maximumSize, 0);
vector<string> graphpaths;
string path;
vector<int> green(maximumSize, 0);
template<class Type>
void showContent1D(Type& input)
for(int i=0; i<input.size(); ++i)
cout<<input[i]<<", ";
return;
void showContentVectorString(vector<string>& input)
for(int i=0; i<input.size(); ++i)
cout<<input[i]<<", ";
return;
void createGraph()
cin>>vertices>>edges;
int vertex0, vertex1;
for(int i=1; i<=edges; ++i)
cin>>vertex0>>vertex1;
graph[vertex0].push_back(vertex1);
graph[vertex1].push_back(vertex0);
for(int i=1; i<=vertices; ++i)
cin>>green[i];
return;
void dfs0(int current, int previous)
if(visited0[current]==1)
return;
visited0[current]=1;
distances[current]=0;
for(int next : graph[current])
if(next==previous)
continue;
dfs0(next, current);
distances[current]=max(distances[current], distances[next]+1);
return;
void dfs1(int root, int current, int previous)
if(visited1[current]==1)
return;
visited1[current]=1;
if(green[current]==1)
if(distances[current]!=0)
path.append(to_string(current));
path.append("->");
else
path.append(to_string(current));
graphPaths.push_back(path);
path.pop_back();
for(int next : graph[current])
if(next==previous)
continue;
dfs1(root, next, current);
if(root==previous)
path.clear();
path.append(to_string(root));
path.append("->");
return;
void solve()
createGraph();
dfs0(1, 0);
dfs1(1, 1, 0);
cout<<"graphPaths: ";
showContentVectorString(graphPaths);
cout<<endl;
return;
int main()
solve();
return 0;
输入:
11 10
1 2
1 3
2 4
2 5
4 8
4 9
3 6
3 7
7 10
10 11
1
1
1
1
0
0
1
0
1
1
0
结果如下:
graphPaths: 1->2->4->9,
如果您需要解决方案的解释,请写下相应的评论。
【讨论】:
【参考方案2】:您的 DFS 递归将有两种基本情况:
负一:当前节点不是绿色的。 肯定的:当前节点是一片绿叶,即它没有子节点。在所有其他情况下,必须对节点的子节点进行递归调用。一旦递归调用返回肯定结果,该肯定结果就可以用当前节点扩展并立即返回,从而中断循环。
实现树的方式有多种,所以我在这个 javascript 实现中做了一些选择:
function findGreenPath(tree, label)
let root = tree[label];
if (!root.green) return null; // No path through none-green node
if (root.children == "") return label; // It is a leaf, start a path
for (let child of root.children)
let path = findGreenPath(tree, child);
if (path != null) return label + path; // prepend this node to a good path
return null; // No path found
// Implementation of the example tree in the question:
let tree = // Dictionary of nodes by their label
"A": green: true, children: "BC",
"B": green: true, children: "DE",
"C": green: true, children: "FG",
"D": green: true, children: "HI",
"E": green: false, children: "",
"F": green: false, children: "",
"G": green: true, children: "J",
"H": green: false, children: "",
"I": green: true, children: "",
"J": green: true, children: "K",
"K": green: false, children: ""
;
let path = findGreenPath(tree, "A");
console.log(path); // ABDI
【讨论】:
【参考方案3】:这很简单。如您所知,DFS 可以通过堆栈来实现。这样我们将树的根压入堆栈,然后弹出堆栈顶部并压入弹出节点的子节点。我们继续这个过程直到有一个空堆栈。
现在,对于您的情况,在将节点推入堆栈之前,您需要检查指定节点(即弹出节点的子节点)是活动的还是非活动的。在这种情况下,您不会在到达非活动节点时向下搜索。最后,只报告所有生成的路径,它们的结束节点是叶子(您可以在搜索过程中轻松找到叶子,一个没有任何子节点的节点)。
【讨论】:
但是我如何避免得到 'A-B-D' 的结果(假设首先检查 A-B-D-H,并且 H 因为不活动而被忽略)? @Misa 只需检查结束节点是否为叶子。请检查更新。 啊,我明白了。非常感谢!以上是关于树递归 - 如何在深度优先搜索中包含条件?的主要内容,如果未能解决你的问题,请参考以下文章