树递归 - 如何在深度优先搜索中包含条件?

Tree recursion - how to include conditions in depth-first search?

我有一棵树(非二进制、不平衡、无循环),所有节点都有标志(绿色=活动,红色=不活动)。我从根节点开始,我必须找到所有节点都处于活动状态的完整路径(从根到叶)。 (至少找到一条路径就可以了。)因此,我需要路径,而不仅仅是信息(如果有的话)。

我正在考虑使用深度优先搜索,但我不知道如何包含 active/inactive 的过滤。有什么想法吗?

很简单。大家知道,DFS可以用栈来实现。这样我们就将树的根压入栈中,然后弹出栈顶并压入弹出节点的子节点。我们继续这个过程直到有一个空堆栈。

现在,对于您的情况,就在将节点压入堆栈之前,您需要检查指定节点(即弹出节点的子节点)是活动的还是非活动的。在这种情况下,您将不会在到达非活动节点时向下搜索。最后,只报告所有生成的路径,其结束节点是叶子(您可以在搜索时轻松找到叶子,一个没有任何子节点的节点)。

您的 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

假设

        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, 

如果您需要解决方案的解释,请写下相应的评论。