网站上声明的问题是
Atul正在进入图论,他现在正在学习树木。他观察到从给定树T中去除边缘将导致形成两个独立的树T1和T2。
树T的每个顶点都被赋予一个正整数。您的任务是删除边缘,以便最小化结果树的Tree_diff。 Tree_diff定义如下:
F(T)=写在树T的每个顶点上的数字之和
Tree_diff(T)= abs(F(T1) - F(T2))
输入格式 第一行将包含整数N,即树中顶点的数量。 下一行将包含由单个空格分隔的N个整数,即分配给每个顶点的值(其中第一个是树的根)。 下一个N-1行包含一对整数,每个整数由一个空格分隔,表示树的边缘。 在上面的输入中,顶点的编号从1到N.
输出格式 包含Tree_diff最小值的单行。
Constraints
3≤N≤10^5
1≤ number written on each vertex ≤1001
以下是问题的link
所以我所做的是使用递归dfs计算所有子树的wts之和,包括最大的树,即=顶点值的总和。
现在当我们删除边缘时说u-v,u是父节点,差异可以简单地计算为:
abs(w[tree[0][u]-1]-(tot-w[tree[0][u]-1]))
其中
tree[0][u]=v
tot=total sum of all vertices weights.
w[tree[0][u]-1] = sum of wts of all vertices of subtree rooted at vertex v
F(T1)=(tot-w[tree[0][u]-1])
F(T2)=(w[tree[0][u]-1])
如果不是留下孩子,我们将拥有正确的孩子
tree[1][u]-1]
而不是
tree[0][u]-1]
第一行是否在tree [] []数组或第二行中包含left child并不重要因为结构可能会改变,但答案将保持不变。
这是我的java代码
import java.io.*;
import java.util.*;
public class Dfs {
static int n;
static int [][]tree = new int[2][100000];
static long []wt=new long[100000];
static long []w=new long[100000];
static int []con=new int[100000];
static int root=0;
static long min=Long.MAX_VALUE;
static long tot=0;
public static void main(String[] args)throws IOException
{
/* Enter your code here. Read input from STDIN. Print output to STDOUT. Your class should be named Solution. */
BufferedReader br=new BufferedReader(new InputStreamReader(System.in));
String []sa;int i,u,v;
n=Integer.parseInt(br.readLine());
sa=br.readLine().split(" ");i=0;
for(String s:sa)
wt[i++]=Long.parseLong(s);
for(i=0;i<n-1;++i)
{
sa=br.readLine().split(" ");
u=Integer.parseInt(sa[0]);
v=Integer.parseInt(sa[1]);
if(i==0)
{
tree[0][u-1]=v;
root=u;
}
else
{
if(con[u-1]==-1)
{
if(tree[0][u-1]==0)
tree[0][u-1]=v;
else tree[1][u-1]=v;
}
else
{
if(tree[0][v-1]==0)
tree[0][v-1]=u;
else tree[1][v-1]=u;
}
}
con[u-1]=-1;
con[v-1]=-1;
}
tot=dfs(root);
w[root-1]=tot;
for(i=0;i<n;++i)
{
if(tree[0][i]!=0)
{
if(min>Math.abs(w[tree[0][i]-1]-(tot-w[tree[0][i]-1])))
min=Math.abs(w[tree[0][i]-1]-(tot-w[tree[0][i]-1]));
}
if(tree[1][i]!=0)
{
if(Math.abs(w[tree[1][i]-1]-(tot-w[tree[1][i]-1]))<min)
min=Math.abs(w[tree[1][i]-1]-(tot-w[tree[1][i]-1]));
}
}
System.out.println(min);
}
static long dfs(int v)
{
long s1=0,s2=0;
if(tree[0][v-1]!=0)
{s1=dfs(tree[0][v-1]);w[tree[0][v-1]-1]=s1;}
if(tree[1][v-1]!=0)
{s2=dfs(tree[1][v-1]);w[tree[1][v-1]-1]=s2;}
return wt[v-1]+s1+s2;
}
}
问题在于它对大多数测试用例给出了错误的答案。我哪里出错了?
答案 0 :(得分:1)
我看到三个方面可能会使您的代码无法通过测试:
您的代码假定树是二叉树。我不确定你能否承担这一点,因为在挑战中没有提到。因此,您的数据结构会受到质疑,因为您为向左分支保留 tree [0] ,为向右分支保留 tree [1] 。相反,您应该从下到上构建您的树,采用parent[i] = j
种结构。
其次,您的代码将根顶点定义为第一个边的第一个顶点。但这似乎是不必要的,甚至可能是错误的:它表示关于“第一个是根”的顶点,所以这意味着你应该在所有情况下设置root=1
。是否指定了第一个列出的边是否具有根作为最左侧顶点。
此外,您的代码假设边缘序列的顺序是至少其顶点之一已经是您正在构建的树的一部分,但这可能无法保证。边缘可以按任何顺序列出,至少挑战在这方面没有做出任何承诺。发生这种情况时,您的代码假定两个顶点中的第一个( u )是第二个( v )的子节点,但很可能它应该是在另一个方向。要解决这个问题,您需要以递归方式浏览边缘列表,确保只在确定边缘方向时才添加边缘。
主要是因为第1点,你的算法需要做一些修改。