我遇到了代码挑战,我想要提示。
问题:您将获得一个树数据结构(没有循环),并被要求尽可能多地删除“边缘”(连接),创建具有偶数个节点的较小树。由于存在偶数个节点和连接,因此始终可以解决此问题。
您的任务是计算删除的边缘。
输入: 第一行输入包含两个整数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)时,我们可以得到所需的结果。
答案 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)
这是我用来成功传递所有测试用例的方法。
答案 6 :(得分:0)
以下是替代方法的概要:
答案 7 :(得分:0)
解决方案 - 遍历所有边缘,并计算偶数边数
如果我们从树中移除一条边并导致两棵树具有偶数个顶点,那么让我们调用该边 - 甚至是边
如果我们从树中移除边缘并且它导致两个奇数树 顶点数量,让我们称之为边缘 - 奇数边缘
这是我在Ruby中的解决方案
display: block
注意 - Click Here检查图表,节点和边缘类的代码