在树中删除,但仅删除某些节点

时间:2019-04-07 14:10:02

标签: c++ algorithm graph tree

https://i.stack.imgur.com/JAz2M.png

这是问题所在。 我有密码。但以某种方式无法通过所有测试用例。我生成的所有测试用例都是真实的。你能告诉我为什么我弄错了吗?

将为您提供N个目录/文件夹的目录树。每个目录都由一个从1到N的特定目录表示。根目录的ID为1,那么它有一些子目录,这些目录可能包含其他一些目录,然后继续。现在,您将获得要删除的目录ID的列表,您需要找到需要删除的最小目录数,以便删除给定列表中的所有目录。

vector<vector<int> > adj;
vector<bool> del;
vector<bool> col;
void Final(int a, bool val)
{
    col[a] = val;
    if (del[a])
        val = del[a];
    for (int i = 0; i < adj[a].size(); i++) {
        Final(adj[a][i], val);
    }
    return;
}
int main()
{
    int n;
    cin >> n;
    adj.resize(n + 1);
    adj.clear();
    for (int i = 1; i <= n; i++) {
        int a;
        cin >> a;
        adj[a].push_back(i);
    }
    int q;
    cin >> q;
    if (q <= 1) {
        cout << q << endl;
        return 0;
    }
    del.resize(n + 1);
    col.resize(n + 1);
    del.clear();
    col.clear();
    for (int i = 0; i <= n; i++) {
        col[i] = false;
        del[i] = false;
    }
    for (int i = 0; i < q; i++) {
        int a;
        cin >> a;
        del[a] = true;
    }
    if (del[1]) {
        cout << "1" << endl;
        return 0;
    }
    else {
        Final(1, false);
        int final = q;
        for (int i = 1; i <= n; i++) {
            if (del[i] && col[i])
                final--;
        }
        cout << final << " ";
    }
}

2 个答案:

答案 0 :(得分:1)

使用DFS!

如果根标记为“待删除”,则返回1(这是最好的情况,工作最少)。否则,递归到根的每个子节点,并将它们加起来以知道要删除的节点数。不变的是:如果要删除节点,请不要再重新使用子树(因为植根于该子树的所有内容都会消失)

这是一些伪代码

DFS(root)
    if(root is to be deleted)
        return 1
    else 
        number_of_nodes_to_delete = 0;
        for every child c of root
            number_of_nodes_to_delete += DFS(c)
        return number_of_nodes_to_delete;

您显然有正确的想法将树表示为邻接列表vector<vector<int>>

作为次要细节,将邻接列表作为const&传递到递归中。这样可以节省复印时间。 (DFS(int root, const vector<vector<int>>& adjList可能是有用的函数签名)。

答案 1 :(得分:0)

我已经使用Java解决了同样的问题。下面是代码。

// Function to add an edge into the graph
void addEdge(int v, int w) {
    adj[v].add( w); // Add w to v’s list.
}

 public int DFS(int s, Set<Integer> tset) {
   // Store the DFS travel which does not contain child nodes to be deleted
    List<Integer> dfs_travel = new Vector<>();
    // Initially mark all vertices as not visited
    List<Boolean> visited = new Vector<Boolean>(V);
    for (int i = 0; i <= V; i++)
        visited.add(false);

    // Create a stack for DFS
    Stack<Integer> stack = new Stack<>();

    // Push the current source node
    stack.push(s);

    while (stack.empty() == false) {
        // Pop a vertex from stack and print it
        s = stack.pop();

        // Stack may contain same vertex twice. So
        // we need to print the popped item only
        // if it is not visited.
        // Also check whether the element is part of elements to be remove
        if (visited.get(s) == false && tset.contains(s)) {
            dfs_travel.add(s);
            visited.set(s, true);
        }

        // Get all adjacent vertices of the popped vertex s
        // If a adjacent has not been visited, 
        // and it is not in delete set then push it
        // to the stack.
        if (!tset.contains(s)) {
            Iterator<Integer> itr = adj[s].iterator();
            while (itr.hasNext()) {
                int v = itr.next();
                if (!visited.get(v))
                    stack.push(v);
            }
        }
    }
    return dfs_travel.size();
}

private int processDirectoryDeletion(int n, int[] folders, int m,
        int[] idsTodelete) {
    TestClass g = new TestClass(n);

    Set<Integer> tset = new HashSet<Integer>();
    for (int i = 0; i < idsTodelete.length; i++) {
        tset.add(idsTodelete[i]);
    }
    g.addEdge(0, 1);
    int ans = 0;
    for (int i = 1; i < n; i++) {
        g.addEdge(folders[i], i + 1);
    }
    return g.DFS(1, tset);
  }