-
Notifications
You must be signed in to change notification settings - Fork 111
/
Copy pathsolution.java
154 lines (126 loc) · 5.48 KB
/
solution.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
// Balanced Forest problem from hackerrank.
import java.io.FileReader;
import java.io.IOException;
import java.util.*;
public class Balanced_Forest {
public static void main(String[] args) throws IOException {
// BufferedWriter bufferedWriter = new BufferedWriter(new FileWriter(System.getenv("OUTPUT_PATH")));
long t1 = System.nanoTime();
Scanner scanner = new Scanner(new FileReader("in.txt")) ;//System.in);
int q = scanner.nextInt();
scanner.skip("(\r\n|[\n\r\u2028\u2029\u0085])?");
for (int qItr = 0; qItr < q; qItr++) {
int n = scanner.nextInt();
scanner.skip("(\r\n|[\n\r\u2028\u2029\u0085])?");
int[] c = new int[n];
String[] cItems = scanner.nextLine().split(" ");
scanner.skip("(\r\n|[\n\r\u2028\u2029\u0085])?");
for (int i = 0; i < n; i++) {
int cItem = Integer.parseInt(cItems[i]);
c[i] = cItem;
}
int[][] edges = new int[n - 1][2];
for (int i = 0; i < n - 1; i++) {
String[] edgesRowItems = scanner.nextLine().split(" ");
scanner.skip("(\r\n|[\n\r\u2028\u2029\u0085])?");
for (int j = 0; j < 2; j++) {
int edgesItem = Integer.parseInt(edgesRowItems[j]);
edges[i][j] = edgesItem;
}
}
long result = balancedForest(c, edges);
System.out.println("ANSWER: " + result);
}
scanner.close();
long t2 = System.nanoTime();
// System.out.println("time: " + (t2-t1)/1e6);
}
static class Node {
long cost;
boolean visited=false, v2=false;
ArrayList<Integer> adjacent = new ArrayList<>();
@Override
public String toString() {
return "Node{" +
"cost=" + cost +
", v1=" + visited +
", v2=" + v2 +
", adjacent=" + adjacent +
'}';
}
public Node(long cost) {
this.cost = cost;
}
}
static long mini, sum;
static HashSet<Long> s = new HashSet<>();
static HashSet<Long> q = new HashSet<>();
static long balancedForest(int[] node_values, int[][] edges) {
s = new HashSet<>();
q = new HashSet<>();
ArrayList<Node> nodes = new ArrayList<>();
for (int i = 0; i < node_values.length; i++) {
nodes.add(new Node(node_values[i]));
}
for (int i = 0; i < edges.length; i++) {
int[] edge = edges[i];
int a = edge[0] - 1;
int b = edge[1] - 1;
nodes.get(a).adjacent.add(b);
nodes.get(b).adjacent.add(a);
}
mini = sum = dfs(0, nodes);
solve(0, nodes);
return mini == sum ? -1 : mini;
}
// s contains sums encountered during depth first search excluding those from the root to the current node.
// q contains sums encountered during depth first search from the root to current node.
private static void solve(int p, ArrayList<Node> nodes) {
Node node = nodes.get(p);
if (node.v2) return;
node.v2 = true;
long[] x = {2*node.cost,
2*sum - 4*node.cost,
sum-node.cost};
long[] y = {3*node.cost - sum,
(sum-node.cost)/2 - node.cost};
// If removing the edge above the current node (node variable defined at the top of this method)
// gives two trees whose total values are the same, then the node we add should have that
// same value too to get 3 trees (one of which is our single node that we added) with the same value.
if (sum % 2 == 0 && node.cost == (sum/2)) mini = Math.min(mini, sum/2);
// case 1a: When two non-overlapping subtrees in the overall tree have the same total value.
if (s.contains(node.cost)) {// || // case 1a
// q.contains(2*node.cost) ) { // ?
if (y[0] >= 0) mini = Math.min(mini, y[0]);
}
// case 1b: (part B): Two non-overlapping subtrees in the overall tree.
// case 2b: One edge to be removed is below the other edge to be removed in the overall tree.
if (s.contains(sum - 2*node.cost) || // case 1b (part B)
q.contains(sum - node.cost) ) { // case 2b
if (y[0] >= 0) mini = Math.min(mini, y[0]);
}
// case 1b: (part A): Two non-overlapping subtrees in the overall tree.
// case 2a: One edge to be removed is below the other edge to be removed in the overall tree.
if ((sum - node.cost) % 2 == 0) {
if (s.contains((sum-node.cost) / 2 ) || // case 1b (part A)
q.contains((sum + node.cost) / 2)) { // case 2a
if (y[1] >= 0) mini = Math.min(mini, y[1]);
}
}
q.add(node.cost);
for (int i = 0; i < node.adjacent.size(); i++) { // DFS!!
solve(node.adjacent.get(i), nodes); // recursive call
}
q.remove(node.cost);
s.add(node.cost);
}
private static long dfs(int p, ArrayList<Node> nodes) {
Node node = nodes.get(p);
if (node.visited) return 0;
node.visited = true;
for (int i = 0; i < node.adjacent.size(); i++) {
node.cost += dfs(node.adjacent.get(i), nodes);
}
return node.cost;
}
}