【问题标题】:Obtain forest out of tree with even number of nodes从偶数个节点的树中获取森林
【发布时间】:2012-08-20 18:44:39
【问题描述】:

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

问题:给您一个树数据结构(没有循环),并要求您删除尽可能多的“边”(连接),从而创建具有偶数个节点的较小树。这个问题总是可以解决的,因为有偶数个节点和连接。

你的任务是计算被移除的边数。

输入: 输入的第一行包含两个整数 N 和 M。N 是顶点数,M 是边数。 2

输出: 打印移除的边数。

示例输入

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),我们可以得到想要的结果。

【问题讨论】:

  • 介意为其他人发布您的解决方案吗?
  • 你的图是定向的吗?我通过计算有向图来解决它,并且只有 3 个案例通过
  • 不是有向图。我使用 bfs 遍历节点。

标签: algorithm tree


【解决方案1】:

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

在得到所有节点的子节点数后得到数组后,只需计算节点数为偶数的节点即可给出答案。注意:我在最后一步的计数中没有包括根节点。

【讨论】:

  • 为什么答案是这样的,除了根节点之外,具有偶数个后继节点的节点是正确的答案?首先如何考虑这个问题
  • @user595169 原因是为了能够将一棵树拆分成偶数组件,树中的节点数必须是偶数。因此,它遵循的值是 root 将是一个偶数
  • 为什么要使用“child”、“leaf”和“root”这些词?树是无向图(en.wikipedia.org/wiki/Tree_(graph_theory))。 hackerrank 的图像不显示方向,也不使用这些词。还是我误解了问题?
  • 所以选择任何一个节点并称之为根,你将得到有效的树。
  • 我认为只有根节点可以有两个以上的孩子。如果这是真的,那么你不能选择另一个节点作为根,如果任何节点有两个以上的孩子。
【解决方案2】:

这是我的解决方案。我没有使用 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);

        }

}

【讨论】:

  • 这一行:tree[u1-1] = v1; 假设节点是有序的,很抱歉,但这是有缺陷的
  • @decebal 没错!然而 Eren 的解决方案可以通过 HackerRank 上的所有案例 - hackerrank.com/challenges/even-tree
【解决方案3】:

如果你观察输入,你会发现统计每个节点下的节点数是相当容易的。将 (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)

【讨论】:

  • 我想在这里有所不同,使用以下测试用例,您提到的策略输出应为 6,而输出应为 4:20 19 2 1 3 1 4 3 5 2 6 5 7 1 8 1 9 2 10 7 11 10 12 3 13 7 14 8 15 12 16 6 17 6 18 10 19 1 20 8 请解释策略!
【解决方案4】:

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

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);
        }
    }
}

【讨论】:

    【解决方案5】:

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

    【讨论】:

      【解决方案6】:

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

      1. 将顶点 1 标记为根
      2. 从当前根顶点开始,考虑每个子节点。如果孩子及其所有孩子的总和是偶数,那么您可以切割该边
      3. 下降到下一个顶点(根顶点的子节点),并让它成为新的根顶点。重复第 2 步,直到遍历完所有节点(深度优先搜索)。

      【讨论】:

        【解决方案7】:

        以下是另一种方法的概要:

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

        【讨论】:

          【解决方案8】:

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

          如果我们从树中删除一条边,并导致两棵树的顶点数为偶数,我们称该边为偶数边

          如果我们从树中删除一条边,它会导致两棵树的奇数 顶点的数量,我们称之为边 - 奇边

          这是我在 Ruby 中的解决方案

          num_vertices, num_edges = gets.chomp.split(' ').map { |e| e.to_i }
          graph = Graph.new
          (1..num_vertices).to_a.each do |vertex|
            graph.add_node_by_val(vertex)
          end
          
          num_edges.times do |edge|
            first, second = gets.chomp.split(' ').map { |e| e.to_i }
            graph.add_edge_by_val(first, second, 0, false)
          end
          
          even_edges = 0
          graph.edges.each do |edge|
            dup = graph.deep_dup
            first_tree = nil
            second_tree = nil
            subject_edge = nil
            dup.edges.each do |e|
              if e.first.value == edge.first.value && e.second.value == edge.second.value
                subject_edge = e
                first_tree = e.first
                second_tree = e.second
              end
            end
            dup.remove_edge(subject_edge)
            if first_tree.size.even? && second_tree.size.even?
              even_edges += 1
            end
          end
          puts even_edges
          

          注意 - Click Here 查看 Graph、Node 和 Edge 类的代码

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 2011-07-26
            • 2017-12-24
            • 2016-10-08
            • 2016-06-26
            • 2021-03-24
            • 2014-04-19
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多