使用偶数节点从树中获取森林

时间:2012-08-20 18:44:39

标签: algorithm tree

我遇到了代码挑战,我想要提示

问题:您将获得一个树数据结构(没有循环),并被要求尽可能多地删除“边缘”(连接),创建具有偶数个节点的较小树。由于存在偶数个节点和连接,因此始终可以解决此问题。

您的任务是计算删除的边缘。

输入: 第一行输入包含两个整数N和M.N是顶点数,M是边数。 2 <= N <= 100。 接下来的M行包含两个整数ui和vi,它们指定树的边缘。 (基于1的指数)

输出: 打印删除的边数。

示例输入

10 9
2 1
3 1
4 3
5 2
6 1
7 2
8 6
9 8
10 8

示例输出: 2

说明:在删除边(1,3)和(1,6)时,我们可以得到所需的结果。

8 个答案:

答案 0 :(得分:23)

我使用BFS浏览节点。 首先,分别维护一个数组以存储子节点的总数+ 1。 因此,您最初可以在此数组中为所有叶节点分配值1。 现在从最后一个节点开始,计算每个节点的子节点数。这将以自下而上的方式工作,存储子节点数的数组将在运行时帮助优化代码。

在获得所有节点的子节点数后获得数组后,只计算具有偶数节点数的节点就可以得到答案。注意:我在最后一步计算中没有包含根节点。

答案 1 :(得分:6)

这是我的解决方案。我没有使用bfs树,只是分配了另一个数组来保存每个节点及其子节点的总数。

import java.util.Scanner;
import java.util.Arrays;

public class Solution {
        public static void main(String[] args) {
                int tree[];
                int count[];

                Scanner scan = new Scanner(System.in);

                int N = scan.nextInt(); //points
                int M = scan.nextInt();

                tree = new int[N];
                count = new int[N];
                Arrays.fill(count, 1);

                for(int i=0;i<M;i++)
                {
                        int u1 = scan.nextInt();
                    int v1 = scan.nextInt();

                    tree[u1-1] = v1;

                    count[v1-1] += count[u1-1];

                    int root = tree[v1-1];

                    while(root!=0)
                    {
                        count[root-1] += count[u1-1];
                        root = tree[root-1];
                    }
                }

                System.out.println("");

                int counter = -1;
                for(int i=0;i<count.length;i++)
                {
                        if(count[i]%2==0)
                        {
                                counter++;
                        }

                }
                System.out.println(counter);

        }

}

答案 2 :(得分:2)

如果观察输入,可以看到计算每个节点下的节点数非常容易。考虑(a b)作为边输入,在每种情况下,a是子,b是直接父。输入始终具有自下而上表示的边。

所以它本质上是具有偶数的节点数(不包括根节点)。我在Hackerrank上提交了以下代码并通过了所有测试。我猜输入中的所有情况都满足规则。

def find_edges(count):
    root = max(count)

    count_even = 0

    for cnt in count:
        if cnt % 2 == 0:
            count_even += 1

    if root % 2 == 0:
        count_even -= 1

    return count_even

def count_nodes(edge_list, n, m):
    count = [1 for i in range(0, n)]

    for i in range(m-1,-1,-1):
        count[edge_list[i][1]-1] += count[edge_list[i][0]-1]

return find_edges(count)

答案 3 :(得分:2)

我知道这已经在这里回答了很多很多时间。我仍然想知道我的解决方案的评论。我尝试构造子计数,因为边缘通过输入传递,并且它通过了所有测试用例。

namespace Hackerrank
{
    using System;
    using System.Collections.Generic;
    using System.Linq;

    class Program
    {
        static void Main(string[] args)
        {
            var tempArray = Console.ReadLine().Split(' ').Select(x => Convert.ToInt32(x)).ToList();
            int verticeNumber = tempArray[0];
            int edgeNumber = tempArray[1];

            Dictionary<int, int> childCount = new Dictionary<int, int>();

            Dictionary<int, int> parentDict = new Dictionary<int, int>();

            for (int count = 0; count < edgeNumber; count++)
            {
                var nodes = Console.ReadLine().Split(' ').Select(x => Convert.ToInt32(x)).ToList();
                var node1 = nodes[0];
                var node2 = nodes[1];

                if (childCount.ContainsKey(node2))
                    childCount[node2]++;
                else childCount.Add(node2, 1);

                var parent = node2;
                while (parentDict.ContainsKey(parent))
                {
                    var par = parentDict[parent];
                    childCount[par]++;
                    parent = par;
                }

                parentDict[node1] = node2;
            }

            Console.WriteLine(childCount.Count(x => x.Value % 2 == 1) - 1);
        }
    }
}

答案 4 :(得分:1)

我的第一个倾向是从叶节点处理,因为你不能切割它们的边缘,因为它会留下单顶点子树。

答案 5 :(得分:1)

这是我用来成功传递所有测试用例的方法。

  1. 将顶点1标记为根
  2. 从当前根顶点开始,考虑每个子节点。如果孩子及其所有孩子的总和是均匀的,那么你可以削减这一优势
  3. 下降到下一个顶点(根顶点的子节点)并让它成为新的根顶点。重复步骤2,直到遍历所有节点(深度优先搜索)。

答案 6 :(得分:0)

以下是替代方法的概要:

  1. 查找图表中的所有articulation points
  2. 检查每个关节点,看看是否可以去除边缘。
  3. 删除合法边缘并寻找更多关节点。

答案 7 :(得分:0)

解决方案 - 遍历所有边缘,并计算偶数边数

如果我们从树中移除一条边并导致两棵树具有偶数个顶点,那么让我们调用该边 - 甚至是边

如果我们从树中移除边缘并且它导致两个奇数树 顶点数量,让我们称之为边缘 - 奇数边缘

这是我在Ruby中的解决方案

display: block

注意 - Click Here检查图表,节点和边缘类的代码