【问题标题】:Cut the tree ,most of test cases evaluating incorrect砍树,大多数测试用例评估不正确
【发布时间】:2017-02-18 08:26:09
【问题描述】:

网站上说的问题是

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 计算所有子树的 wt 总和,包括最大的树,也就是 = 顶点值的总和。

现在,当我们删除一条边说 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[][]数组中的左子还是第二行都没有关系,因为结构可能会改变,但答案将保持不变。

这是我的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;
    }    
}

问题是它对大多数测试用例给出了错误的答案。我哪里出错了?

【问题讨论】:

标签: algorithm tree depth-first-search


【解决方案1】:

我看到三个方面可能使您的代码无法通过测试:

  1. 您的代码假定树是二叉树。我不确定您是否可以假设这一点,因为挑战中没有提到它。这样一来,您的数据结构就会受到质疑,因为您将 tree[0] 保留给左分支,将 tree[1] 保留给右分支。相反,您可能应该以 parent[i] = j 类型的结构自下而上构建您的树。

  2. 其次,您的代码将根顶点定义为第一条边的第一个顶点。但这似乎是不必要的,甚至可能是错误的:它说关于顶点“第一个是根”,所以这只是意味着你应该在所有情况下设置root=1。未指定列出的第一条边是否以根为最左边的顶点。

  3. 1234563边缘可以按任何顺序列出,至少挑战在这方面没有做出任何承诺。发生这种情况时,您的代码假定两个顶点中的第一个 (u) 是第二个顶点 (v) 的子级,但它很可能应该是在另一个方向。要解决这个问题,您需要以递归方式遍历边列表,确保仅在确定边的方向时才添加边。

主要是因为第 1 点,您的算法需要大量返工。

【讨论】:

    猜你喜欢
    • 2021-02-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-08-01
    • 2012-02-13
    • 1970-01-01
    • 2016-03-11
    • 2017-12-20
    相关资源
    最近更新 更多