Get Main Line From Graph - algorithm

I am Facing a problem that requires some sort of an algorithm which allows me to get main line from a graph. A main line is basically a feeder network. On a graph it would be the main nodes that feeds sub nodes. Picture below explains.
so the main line in the diagram above would be 1, 2, 3, 4, 5. Each node contains a property which is the list of connected nodes; So number 3 would contain 2, 4, and 10. I started thinking that first I should get rid of the nodes that has one connected to them, but that will leave me with some unwanted nodes as well, hence if I were to remove 6, 7, 8 ,9, 11, 13, 12 I'd still have an unwanted node of 10.
For those of you that do not understand what a feeder network is, it is basically a bunch of structures, manholes, handholes, cabinets, that carry the signal from the root structure 1 distributing it to areas through 2, 3, 4, and 5, till it reaches the customers. 6, 7, 8, 11, 13, 12, 9. as for 10, it is a sub manhole structure that simply is not part of the main network because it distributes within the branch. now I know what those are, but in the code. those are all nothing but a bunch of objects that contain what they are connected to. no types no nothing.

Following from the partial answer that you'd given, I think adding another property will give you the solution.
So far, you have 1,2,3,4,5 and 10.
The problem is 10, as we know, should not be part of the feeder network (since it's a branch).
If you look back, you can see that, for all nodes except 10, there's one path from node to source and one path from node to destination (the last node that you have have selected through your process from the queue) without any edge being visited twice.
Ex:
1.) 3->2->1 (source) & 3->4->5 (destination)
2.) 4->3->2->1 (source) & 4->5 (destination)
But in case of 10, one edge is going to be visited twice.
As in,
10->3->2->1 & 10->3->4->5
Here, as you can see, the edge 10-3 is visited twice which does not happen in case of other nodes.
Through this process, any node, which is not part of the feeder network, will be discarded.
From the information provided, this will give the right solution.

I would suggest you recursively search from your starting node. Descend through your nodes keeping track of the number of nodes you have passed though.
keep 2 arrays (or linked lists) one for your current path and one for your longest path. Add nodes to your current array as you descend and remove them as you return. do the same for the longest path array but only add to it as you exceed your current longest path. when you have searched the entire graph remove the last node in your array (since that will not be part of the main path).
There is probably a more efficient way to do this, which I'll have to give some thought to.

This code return the mainline for you:
static void Main()
{
Node node1 = new Node(1, null);
Node node6 = new Node(6, node1);
Node node2 = new Node(2, node1);
Node node7 = new Node(7, node2);
Node node8 = new Node(8, node2);
Node node3 = new Node(3, node2);
Node node10 = new Node(10, node3);
Node node8_ = new Node(8, node10);
Node node11 = new Node(11, node10);
Node node4 = new Node(4, node3);
Node node5 = new Node(5, node4);
Node node12 = new Node(12, node5);
Node node13 = new Node(13, node5);
List<List<Node>> MainLines = new List<List<Node>>();
foreach (var i in Node.HighestRankNodes)
{
List<Node> m = new List<Node>();
m.Add(i);
Node j = i.Parent;
while (j != null)
{
m.Insert(0, j);
j = j.Parent;
}
MainLines.Add(m);
}
foreach (var i in MainLines) Console.WriteLine("Mainline: " + string.Join(", ", i));
Console.ReadLine();
}
Node class:
public class Node
{
public int Number;
public Node Parent = null;
public int Rank = 0;
public static int currentMaxRank = 0;
public static List<Node> HighestRankNodes = new List<Node>();
public Node(int number, Node parent)
{
Number = number;
Parent = parent;
Rank = Parent != null ? Parent.Rank + 1 : 0;
if (currentMaxRank < Rank)
{
currentMaxRank = Rank;
HighestRankNodes.Clear();
}
if (currentMaxRank == Rank) HighestRankNodes.Add(this);
}
public override string ToString()
{
return Number.ToString();
}
}
Output:
Mainline: 1, 2, 3, 4, 5, 12
Mainline: 1, 2, 3, 4, 5, 13

Related

Finding the mode in Binary Search Tree

I saw this question has been around on this site, but I would like to discuss one issue please about tracking prev value in the code below. Given the following solution for finding the Mode in binary search tree,
class Solution {
Integer prev = null;
int count = 1;
int max = 0;
public int[] findMode(TreeNode root) {
//this is expandable, but int [] array is not expandable
List<Integer> modes = new ArrayList();
traverse(root, modes);
int[] result = new int[modes.size()];
for (int i=0; i<modes.size(); i++){
result[i] = modes.get(i);
}
return result;
}
//In BST, do inorder since that way nodes will be sorted L < root < R
public void traverse(TreeNode root, List<Integer> modes){
if(root == null) return; //dont do anything
traverse(root.left, modes);
if(prev != null){
if(prev == root.val){
count ++;
} else{
count =1;
}
}
if(count > max){
max = count;
modes.clear(); //delete all previous modes as we find a new one
modes.add(root.val);
} else if(count == max) { // we find another mode that has same # of occurrences
modes.add(root.val);
}
prev = root.val;
traverse( root.right, modes);
}
}
Now, the prev variable is supposed to capture the previous node value so that when we enter to node's left child as the code show, we will immediately compare it to left child of that node. For example, if prev = 5, then once we go up to 10, the new prev is prev = root.val;, then we got to 15 the right child of 10. But we don't compare prev to 15, but to 10 as we immediately go left in the code once, so we compare prev = 10 to node.val in if(prev == root.val) line. We go from there for all other nodes.
Problem: Suppose the node that is immediately left to 30 is 25 and not 20, then the trick used in this solution won't work in this case, what do you think pleas?
The algorithm is performing an in-order tree traversal, which does this:
traverse the left subtree by recursively calling the in-order function.
access the data part of the current node.
traverse the right subtree by recursively calling the in-order function.
In a binary search tree, because of the order of the nodes, an in-order traversal is visiting the nodes in ascending sorted order.
I think this picture (courtesy Wikipedia) will help to explain what's happening:
In-order traversal will visit the nodes in this order:
A, B, C, D, E, F, G, H, I;
Now since we are visiting the nodes is ascending sorted order, duplicates will be grouped together. Therefore, we just need to compare the current node with the previous node to find duplicates.
In your first example tree, the nodes are visited in this order:
5, 10, 10, 12, 15, 15, 16, 18, 20, 20, 20, 20, 25, 28, 30, 32.
The mode is 20.
In your second example tree, the nodes are visited in this order:
5, 10, 10, 12, 15, 15, 16, 18, 20, 20, 20, 25, 30, 32.
The mode is 20.

Construct binary tree given its inorder and preorder traversals without recursion

Given inorder and preorder traversals of a tree, how the tree can be re-constructed in non-recursive manner.
For example:
Re-construct the following tree
1
2 3
4 5 6 7
8 9
given
inorder traversal: 4, 2, 5, 8, 1, 6, 3, 9, 7
preorder traversal: 1, 2, 4, 5, 8, 3, 6, 7, 9
Note: There are many references to recursive implementations. For example, one may refer Construct Tree from given Inorder and Preorder traversals. However intent here is to find non-recursive implementation.
Idea is to keep tree nodes in a stack from preorder traversal, till their counterpart is not found in inorder traversal. Once a counterpart is found, all children in the left sub-tree of the node must have been already visited.
Following is non-recursive Java implementation.
public TreeNode constructTree(int[] preOrder, int[] inOrder) {
if (preOrder.length == 0) {
return null;
}
int preOrderIndex = 0;
int inOrderIndex = 0;
ArrayDeque<TreeNode> stack = new ArrayDeque<>();
TreeNode root = new TreeNode(preOrder[0]);
stack.addFirst(root);
preOrderIndex++;
while (!stack.isEmpty()) {
TreeNode top = stack.peekFirst();
if (top.val == inOrder[inOrderIndex]) {
stack.pollFirst();
inOrderIndex++;
// if all the elements in inOrder have been visted, we are done
if (inOrderIndex == inOrder.length) {
break;
}
// Check if there are still some unvisited nodes in the left
// sub-tree of the top node in the stack
if (!stack.isEmpty()
&& stack.peekFirst().val == inOrder[inOrderIndex]) {
continue;
}
// As top node in stack, still has not encontered its counterpart
// in inOrder, so next element in preOrder must be right child of
// the removed node
TreeNode node = new TreeNode(preOrder[preOrderIndex]);
preOrderIndex++;
top.right = node;
stack.addFirst(node);
} else {
// Top node in the stack has not encountered its counterpart
// in inOrder, so next element in preOrder must be left child
// of this node
TreeNode node = new TreeNode(preOrder[preOrderIndex]);
preOrderIndex++;
top.left = node;
stack.addFirst(node);
}
}
return root;
}

How to implement depth first search for graph with a non-recursive approach

I have spent lots of time on this issue. However, I can only find solutions with non-recursive methods for a tree: Non recursive for tree, or a recursive method for the graph, Recursive for graph.
And lots of tutorials (I don't provide those links here) don't provide the approaches as well. Or the tutorial is totally incorrect. Please help me.
Updated:
It's really hard to describe:
If I have an undirected graph:
1
/ | \
4 | 2
3 /
1-- 2-- 3 --1 is a cycle.
At the step: 'push the neighbors of the popped vertex into the stack', what's the order in which the vertices should be pushed?
If the pushed order is 2, 4, 3, the vertices in the stack are:
| |
|3|
|4|
|2|
_
After popping the nodes, we get the result: 1 -> 3 -> 4 -> 2 instead of 1--> 3 --> 2 -->4.
It's incorrect. What condition should I add to stop this scenario?
A DFS without recursion is basically the same as BFS - but use a stack instead of a queue as the data structure.
The thread Iterative DFS vs Recursive DFS and different elements order handles with both approaches and the difference between them (and there is! you will not traverse the nodes in the same order!)
The algorithm for the iterative approach is basically:
DFS(source):
s <- new stack
visited <- {} // empty set
s.push(source)
while (s is not empty):
current <- s.pop()
if (current is in visited):
continue
visited.add(current)
// do something with current
for each node v such that (current,v) is an edge:
s.push(v)
This is not an answer, but an extended comment, showing the application of the algorithm in #amit's answer to the graph in the current version of the question, assuming 1 is the start node and its neighbors are pushed in the order 2, 4, 3:
1
/ | \
4 | 2
3 /
Actions Stack Visited
======= ===== =======
push 1 [1] {}
pop and visit 1 [] {1}
push 2, 4, 3 [2, 4, 3] {1}
pop and visit 3 [2, 4] {1, 3}
push 1, 2 [2, 4, 1, 2] {1, 3}
pop and visit 2 [2, 4, 1] {1, 3, 2}
push 1, 3 [2, 4, 1, 1, 3] {1, 3, 2}
pop 3 (visited) [2, 4, 1, 1] {1, 3, 2}
pop 1 (visited) [2, 4, 1] {1, 3, 2}
pop 1 (visited) [2, 4] {1, 3, 2}
pop and visit 4 [2] {1, 3, 2, 4}
push 1 [2, 1] {1, 3, 2, 4}
pop 1 (visited) [2] {1, 3, 2, 4}
pop 2 (visited) [] {1, 3, 2, 4}
Thus applying the algorithm pushing 1's neighbors in the order 2, 4, 3 results in visit order 1, 3, 2, 4. Regardless of the push order for 1's neighbors, 2 and 3 will be adjacent in the visit order because whichever is visited first will push the other, which is not yet visited, as well as 1 which has been visited.
The DFS logic should be:
1) if the current node is not visited, visit the node and mark it as visited
2) for all its neighbors that haven't been visited, push them to the stack
For example, let's define a GraphNode class in Java:
class GraphNode {
int index;
ArrayList<GraphNode> neighbors;
}
and here is the DFS without recursion:
void dfs(GraphNode node) {
// sanity check
if (node == null) {
return;
}
// use a hash set to mark visited nodes
Set<GraphNode> set = new HashSet<GraphNode>();
// use a stack to help depth-first traversal
Stack<GraphNode> stack = new Stack<GraphNode>();
stack.push(node);
while (!stack.isEmpty()) {
GraphNode curr = stack.pop();
// current node has not been visited yet
if (!set.contains(curr)) {
// visit the node
// ...
// mark it as visited
set.add(curr);
}
for (int i = 0; i < curr.neighbors.size(); i++) {
GraphNode neighbor = curr.neighbors.get(i);
// this neighbor has not been visited yet
if (!set.contains(neighbor)) {
stack.push(neighbor);
}
}
}
}
We can use the same logic to do DFS recursively, clone graph etc.
Many people will say that non-recursive DFS is just BFS with a stack rather than a queue. That's not accurate, let me explain a bit more.
Recursive DFS
Recursive DFS uses the call stack to keep state, meaning you do not manage a separate stack yourself.
However, for a large graph, recursive DFS (or any recursive function that is) may result in a deep recursion, which can crash your problem with a stack overflow (not this website, the real thing).
Non-recursive DFS
DFS is not the same as BFS. It has a different space utilization, but if you implement it just like BFS, but using a stack rather than a queue, you will use more space than non-recursive DFS.
Why more space?
Consider this:
// From non-recursive "DFS"
for (auto i&: adjacent) {
if (!visited(i)) {
stack.push(i);
}
}
And compare it with this:
// From recursive DFS
for (auto i&: adjacent) {
if (!visited(i)) {
dfs(i);
}
}
In the first piece of code you are putting all the adjacent nodes in the stack before iterating to the next adjacent vertex and that has a space cost. If the graph is large it can make a significant difference.
What to do then?
If you decide to solve the space problem by iterating over the adjacency list again after popping the stack, that's going to add time complexity cost.
One solution is to add items to the stack one by one, as you visit them. To achieve this you can save an iterator in the stack to resume the iteration after popping.
Lazy way
In C/C++, a lazy approach is to compile your program with a larger stack size and increase stack size via ulimit, but that's really lousy. In Java you can set the stack size as a JVM parameter.
Recursion is a way to use the call stack to store the state of the graph traversal. You can use the stack explicitly, say by having a local variable of type std::stack, then you won't need the recursion to implement the DFS, but just a loop.
okay. if you are still looking for a java code
dfs(Vertex start){
Stack<Vertex> stack = new Stack<>(); // initialize a stack
List<Vertex> visited = new ArrayList<>();//maintains order of visited nodes
stack.push(start); // push the start
while(!stack.isEmpty()){ //check if stack is empty
Vertex popped = stack.pop(); // pop the top of the stack
if(!visited.contains(popped)){ //backtrack if the vertex is already visited
visited.add(popped); //mark it as visited as it is not yet visited
for(Vertex adjacent: popped.getAdjacents()){ //get the adjacents of the vertex as add them to the stack
stack.add(adjacent);
}
}
}
for(Vertex v1 : visited){
System.out.println(v1.getId());
}
}
Python code. The time complexity is O(V+E) where V and E are the number of vertices and edges respectively. The space complexity is O(V) due to the worst-case where there is a path that contains every vertex without any backtracking (i.e. the search path is a linear chain).
The stack stores tuples of the form (vertex, vertex_edge_index) so that the DFS can be resumed from a particular vertex at the edge immediately following the last edge that was processed from that vertex (just like the function call stack of a recursive DFS).
The example code uses a complete digraph where every vertex is connected to every other vertex. Hence it is not necessary to store an explicit edge list for each node, as the graph is an edge list (the graph G contains every vertex).
numv = 1000
print('vertices =', numv)
G = [Vertex(i) for i in range(numv)]
def dfs(source):
s = []
visited = set()
s.append((source,None))
time = 1
space = 0
while s:
time += 1
current, index = s.pop()
if index is None:
visited.add(current)
index = 0
# vertex has all edges possible: G is a complete graph
while index < len(G) and G[index] in visited:
index += 1
if index < len(G):
s.append((current,index+1))
s.append((G[index], None))
space = max(space, len(s))
print('time =', time, '\nspace =', space)
dfs(G[0])
Output:
time = 2000
space = 1000
Note that time here is measuring V operations and not E. The value is numv*2 because every vertex is considered twice, once on discovery and once on finishing.
Acutally, stack is not well able to deal with discover time and finish time, if we want to implement DFS with stack, and want to deal with discover time and finish time, we would need to resort to another recorder stack, my implementation is shown below, have test correct, below is for case-1, case-2 and case-3 graph.
from collections import defaultdict
class Graph(object):
adj_list = defaultdict(list)
def __init__(self, V):
self.V = V
def add_edge(self,u,v):
self.adj_list[u].append(v)
def DFS(self):
visited = []
instack = []
disc = []
fini = []
for t in range(self.V):
visited.append(0)
disc.append(0)
fini.append(0)
instack.append(0)
time = 0
for u_ in range(self.V):
if (visited[u_] != 1):
stack = []
stack_recorder = []
stack.append(u_)
while stack:
u = stack.pop()
visited[u] = 1
time+=1
disc[u] = time
print(u)
stack_recorder.append(u)
flag = 0
for v in self.adj_list[u]:
if (visited[v] != 1):
flag = 1
if instack[v]==0:
stack.append(v)
instack[v]= 1
if flag == 0:
time+=1
temp = stack_recorder.pop()
fini[temp] = time
while stack_recorder:
temp = stack_recorder.pop()
time+=1
fini[temp] = time
print(disc)
print(fini)
if __name__ == '__main__':
V = 6
G = Graph(V)
#==============================================================================
# #for case 1
# G.add_edge(0,1)
# G.add_edge(0,2)
# G.add_edge(1,3)
# G.add_edge(2,1)
# G.add_edge(3,2)
#==============================================================================
#==============================================================================
# #for case 2
# G.add_edge(0,1)
# G.add_edge(0,2)
# G.add_edge(1,3)
# G.add_edge(3,2)
#==============================================================================
#for case 3
G.add_edge(0,3)
G.add_edge(0,1)
G.add_edge(1,4)
G.add_edge(2,4)
G.add_edge(2,5)
G.add_edge(3,1)
G.add_edge(4,3)
G.add_edge(5,5)
G.DFS()
I think you need to use a visited[n] boolean array to check if the current node is visited or not earlier.
A recursive algorithm works very well for DFS as we try to plunge as deeply as we can, ie. as soon as we find an un-explored vertex, we're going to explore its FIRST un-explored neighbor right away. You need to BREAK out of the for loop as soon as you find the first un-explored neighbor.
for each neighbor w of v
if w is not explored
mark w as explored
push w onto the stack
BREAK out of the for loop
I think this is an optimized DFS regarding space-correct me if I am wrong.
s = stack
s.push(initial node)
add initial node to visited
while s is not empty:
v = s.peek()
if for all E(v,u) there is one unvisited u:
mark u as visited
s.push(u)
else
s.pop
Using Stack and implementing as done by the call stack in the recursion process-
The Idea is to push a vertex in the stack, and then push its vertex adjacent to it which is stored in a adjacency list at the index of the vertex and then continue this process until we cannot move further in the graph, now if we cannot move ahead in the graph then we will remove the vertex which is currently on the top of the stack as it is unable to take us on any vertex which is unvisited.
Now, using stack we take care of the point that the vertex is only removed from the stack when all the vertices that can be explored from the current vertex have been visited, which was being done by the recursion process automatically.
for ex -
See the example graph here.
( 0 ( 1 ( 2 ( 4 4 ) 2 ) ( 3 3 ) 1 ) 0 ) ( 6 ( 5 5 ) ( 7 7 ) 6 )
The above parenthesis show the order in which the vertex is added on the stack and removed from the stack, so a parenthesis for a vertex is closed only when all the vertices that can be visited from it have been done.
(Here I have used the Adjacency List representation and implemented as a vector of list (vector > AdjList) by using C++ STL)
void DFSUsingStack() {
/// we keep a check of the vertices visited, the vector is set to false for all vertices initially.
vector<bool> visited(AdjList.size(), false);
stack<int> st;
for(int i=0 ; i<AdjList.size() ; i++){
if(visited[i] == true){
continue;
}
st.push(i);
cout << i << '\n';
visited[i] = true;
while(!st.empty()){
int curr = st.top();
for(list<int> :: iterator it = AdjList[curr].begin() ; it != AdjList[curr].end() ; it++){
if(visited[*it] == false){
st.push(*it);
cout << (*it) << '\n';
visited[*it] = true;
break;
}
}
/// We can move ahead from current only if a new vertex has been added on the top of the stack.
if(st.top() != curr){
continue;
}
st.pop();
}
}
}
The following Java Code will be handy:-
private void DFS(int v,boolean[] visited){
visited[v]=true;
Stack<Integer> S = new Stack<Integer>();
S.push(v);
while(!S.isEmpty()){
int v1=S.pop();
System.out.println(adjLists.get(v1).name);
for(Neighbor nbr=adjLists.get(v1).adjList; nbr != null; nbr=nbr.next){
if (!visited[nbr.VertexNum]){
visited[nbr.VertexNum]=true;
S.push(nbr.VertexNum);
}
}
}
}
public void dfs() {
boolean[] visited = new boolean[adjLists.size()];
for (int v=0; v < visited.length; v++) {
if (!visited[v])/*This condition is for Unconnected Vertices*/ {
System.out.println("\nSTARTING AT " + adjLists.get(v).name);
DFS(v, visited);
}
}
}

Build BST from Preorder

Like many newbies, my head blows up from recursion. I looked up a lot of answers/explanations on SO. but I am still unclear on the concept. (This is not homework, I am trying to relearn what I unlearned and recursion was never a string point)
Given a preorder traversal, construct a binary tree. With recursion, it has to be deceptively simple :) but I just can't get it.
I see that the order of the arr has to be in the order nodes are inserted. What bugs me is:
What if the node already has a left/right? How does this work?
How can the recursion insert nodes, in say the following preorder?
12, 10, 6, 13
15 is root, 5, 3 and left
How does 6 get inserted correctly as 10's left child?
12
10 13
6*
Here is the skeleton code:
main()
{
int[] arr = {};
//make the first node a root node.
node n = new node(arr[0]);
buildbst(n, arr, 0)
}
buildbst(node root, int[] arr, int i)
{
if (i == arr.length) return;
if (arr[i] < root.data)
root.left = new node (arr[i]);
else
root.right = new node(arr[i]);
buildbst(root.left, arr, i++);
buildbst(root.right, arr, i++);
}
EDIT:
I just realised, if I pass in the recursive call buildbst(root.left, arr+i, i++)
is that the right way? Or am I approaching this all wrong - a mish-mash of dynamic programming and recursion and divide and conquer...
It can't already have a left / right child. You call it for the root, which has no children to start. Then you call it for the left child and create children where appropriate and call the function for those children and so on. You never visit the left child again once you go right and you can't get to a node from a function called on its child (since there is no connection up the tree, except the recursion stack).
This is what should happen when given 12, 10, 6, 13:
Creates the root 12
Calls buildbst(node(12), arr, 1)
Create node(12).left = node(10)
Calls buildbst(node(10), arr, 2)
Create node(10).left = node(6)
Calls buildbst(node(6), arr, 3)
13 > 12, must be right child of 12, so do nothing
13 > 12, must be right child of 12, so do nothing
Create node(12).right = node(13)
Calls buildbst(node(13), arr, 3)
Oh look, no more elements, we're done.
The above is not what will happen with your code for 2 reasons:
Your code will only create either a left or a right child, not both (because of the if-else))
Your code doesn't have the must be right child of '12' check, which is a little complex
The below code should cover it.
node buildbst(int[] arr)
{
node n = new node(arr[0]);
// 9999999999 is meant to be > than the biggest element in your data
buildbst(n, arr, 1, 9999999999);
return node;
}
int buildbst(node current, int[] arr, int i, int biggestSoFar)
{
if (i == arr.length) return i;
// recurse left
if (arr[i] < current.data)
{
current.left = new node(arr[i++]);
i = buildbst(current.left, arr, i, current.data);
}
// recurse right
if (i < arr.length && arr[i] < biggestSoFar)
{
current.right = new node(arr[i++]);
i = buildbst(current.right, arr, i, biggestSoFar);
}
return i;
}
Explanation:
The purpose of biggestSoFar is to prevent:
15 15
/ /\
5 versus (the correct) 5 20
/ \ /
1 20 1
When recursing left from 15 for example, we need to stop processing elements as soon as we get an element > 15, which will happen when we get 20. Thus we pass current.data and stop processing elements if we get a bigger value.
When recursing right from 5 for example, we need to stop processing elements as soon as we get an element > 15, which will happen when we get 20. Thus we pass biggestSoFar and stop processing elements if we get a bigger value.

Obtain forest out of tree with even number of nodes

I'm stuck on a code challenge, and I want a hint.
PROBLEM: You are given a tree data structure (without cycles) and are asked to remove as many "edges" (connections) as possible, creating smaller trees with even numbers of nodes. This problem is always solvable as there are an even number of nodes and connections.
Your task is to count the removed edges.
Input:
The first line of input contains two integers N and M. N is the number of vertices and M is the number of edges. 2 <= N <= 100.
Next M lines contains two integers ui and vi which specifies an edge of the tree. (1-based index)
Output:
Print the number of edges removed.
Sample Input
10 9
2 1
3 1
4 3
5 2
6 1
7 2
8 6
9 8
10 8
Sample Output :
2
Explanation : On removing the edges (1, 3) and (1, 6), we can get the desired result.
I used BFS to travel through the nodes.
First, maintain an array separately to store the total number of child nodes + 1.
So, you can initially assign all the leaf nodes with value 1 in this array.
Now start from the last node and count the number of children for each node. This will work in bottom to top manner and the array that stores the number of child nodes will help in runtime to optimize the code.
Once you get the array after getting the number of children nodes for all the nodes, just counting the nodes with even number of nodes gives the answer. Note: I did not include root node in counting in final step.
This is my solution. I didn't use bfs tree, just allocated another array for holding eachnode's and their children nodes total number.
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);
}
}
If you observe the input, you can see that it is quite easy to count the number of nodes under each node. Consider (a b) as the edge input, in every case, a is the child and b is the immediate parent. The input always has edges represented bottom-up.
So its essentially the number of nodes which have an even count(Excluding the root node). I submitted the below code on Hackerrank and all the tests passed. I guess all the cases in the input satisfy the rule.
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)
I know that this has already been answered here lots and lots of time. I still want to know reviews on my solution here. I tried to construct the child count as the edges were coming through the input and it passed all the test cases.
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);
}
}
}
My first inclination is to work up from the leaf nodes because you cannot cut their edges as that would leave single-vertex subtrees.
Here's the approach that I used to successfully pass all the test cases.
Mark vertex 1 as the root
Starting at the current root vertex, consider each child. If the sum total of the child and all of its children are even, then you can cut that edge
Descend to the next vertex (child of root vertex) and let that be the new root vertex. Repeat step 2 until you have traversed all of the nodes (depth first search).
Here's the general outline of an alternative approach:
Find all of the articulation points in the graph.
Check each articulation point to see if edges can be removed there.
Remove legal edges and look for more articulation points.
Solution - Traverse all the edges, and count the number of even edges
If we remove an edge from the tree and it results in two tree with even number of vertices, let's call that edge - even edge
If we remove an edge from the tree and it results in two trees with odd
number of vertices, let's call that edge - odd edge
Here is my solution in 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
Note - Click Here to check out the code for Graph, Node and Edge classes

Resources