📜  最小化边缘删除以将 Tree 转换为大小最多为 N/2 的森林

📅  最后修改于: 2022-05-13 01:56:17.408000             🧑  作者: Mango

最小化边缘删除以将 Tree 转换为大小最多为 N/2 的森林

给定一棵有N个节点的树,编号从0 到 N - 1,任务是找到最小的边删除数,这样,树就被转换为森林,其中森林中的每棵树的大小都可以小于等于为⌊N/2⌋。

例子:

方法:解决问题的想法是使用 深度优先搜索

请按照以下步骤解决给定问题:

  • 从给定的输入创建图表。
  • 使用dfs函数计算质心。
    • 如果树有两个质心,那么答案将为 1。
    • 否则,声明一个向量 subtreeSize,它将计算质心所有子节点的子树大小。
  • 使用dfs2函数计算子树大小。
  • 声明两个变量anssum来存储答案和由于删除而删除的节点数。
  • 按降序对 subtreeSize 进行排序。
    • 迭代 subtreeSize 向量。
  • 将当前值加到总和中,并将 ans 加 1。
  • 如果剩余节点数小于等于N/2
    • 打破循环。
  • 最后,返回ans

以下是上述方法的实现:

C++
// C++ Code for the above approach:
#include 
using namespace std;
  
// Function to calculate the
// Centroids of the tree.
void dfs(int n, int par,
         vector* ar,
         vector& size,
         int& cent1, int& cent2,
         int& some, int tot)
{
  
    size[n] = 1;
    int mx = 0;
  
    // Iterate through the children
    // of the current node and
    // store the maximum of the subtree size
    // among the children in the mx variable.
    for (int child : ar[n]) {
  
        if (child != par) {
  
            dfs(child, n, ar, size,
                cent1, cent2, some, tot);
            size[n] += size[child];
            mx = max(mx, size[child]);
        }
    }
  
    mx = max(mx, tot - size[n]);
  
    // If mx is smaller than the maximum
    // subtree size till now,
    // update that and centroids accordingly.
    if (mx < some) {
        some = mx;
        cent1 = n;
        cent2 = -1;
    }
    else if (mx == some) {
        cent2 = n;
    }
}
  
// Function to calculate the subtree
// size of the given node.
void dfs2(int n, int par,
          vector* ar, int& val)
{
  
    val++;
  
    for (int child : ar[n]) {
        if (child != par) {
            dfs2(child, n, ar, val);
        }
    }
}
  
int minimumEdges(int n,
                 vector >& edges)
{
  
    vector ar[n];
    vector size(n, 0);
  
    // Create the graph
    // From the given input.
    for (int i = 0; i < n - 1; i++) {
        ar[edges[i][0]]
            .push_back(edges[i][1]);
        ar[edges[i][1]]
            .push_back(edges[i][0]);
    }
  
    int cent1 = -1, cent2 = -1, some = 1000000;
  
    // Calculate the centroids
    // Using the dfs function.
    dfs(0, -1, ar, size,
        cent1, cent2, some, n);
  
    // If the tree has two centroids,
    // Then the answer will be 1.
    if (cent2 != -1) {
        return 1;
    }
  
    // Declare a vector subtreeSize,
    // Which will calculate the
    // Subtree size of all the children
    // Of the centroid.
    vector subtree_size;
  
    // Calculate the subtree sizes
    // Using the dfs2 function.
    for (int x : ar[cent1]) {
        int val = 0;
        dfs2(x, cent1, ar, val);
        subtree_size.push_back(val);
    }
  
    // Declare two variables, ans and sum,
    // To store the answer
    // And the number of nodes removed
    // Due to the removal of edges.
    int sum = 0;
    int ans = 0;
  
    // Sort the subtreeSize
    // In descending order.
    sort(subtree_size.rbegin(),
         subtree_size.rend());
  
    // Iterate over the “subtreeSize” vector.
    for (int x : subtree_size) {
  
        // Add the current value to the sum
        // And increase the ans by 1.
        sum += x;
        ans++;
  
        // If the remaining nodes are
        // Less than or equal to N / 2,
        // Break the loop.
        if (n - sum <= n / 2) {
            break;
        }
    }
  
    // Finally, return the ans.
    return ans;
}
  
// Driver code
int main()
{
    int N = 3;
    vector > edges
        = { { 0, 1 }, { 0, 2 } };
    cout << minimumEdges(N, edges) << "\n";
    return 0;
}


输出
2

时间复杂度: O(N * log(N))
辅助空间: O(N)