2

I was doing this problem named Even Tree on hackerank:

https://www.hackerrank.com/challenges/even-tree

and initially i had no clue how to cut edges and build a forest out of the tree. So i looked up on the internet, and saw this answer on stackeverflow:

Obtain forest out of tree with even number of nodes

Well just counting number of children looked much simpler, and i implemented it in C++:

#include <iostream>
#include <list>
#include <vector>
using namespace std;

int main() {
  int N, M, ans = 0;
  cin >> N >> M;
  vector<int> tree(N+1);
  vector<int> count(N+1);

  fill(count.begin(), count.end(), 1);
  for(int i = 0; i < M; i++) {
    int p, q;
    cin >> p >> q;
    tree[p] = q;

    int root = tree[p];

    // updating ancesors child count
    while(root) {
      count[root] += count[p];
      root = tree[root];
    }
  }

  int counter = 0;
  // displaying results
  for(int i = 2; i < count.size(); i++) {
    cout << count[i] << " ";
    if(count[i]%2 == 0)
      counter++;
  }
  cout <<"\nans : " <<  counter << endl;
  return 0;
}

My question is: How does this approach work? How number of children associated with the selection of a tree with minimum number of edges? I don't just want to copy the solution and i want to understand the actual logic behind it. Please help

Community
  • 1
  • 1
Rohan Kumar
  • 5,427
  • 8
  • 25
  • 40
  • have you solved the problem already? If yes then I will skip and not post my answer :) – shole Sep 27 '16 at 03:02
  • I would really appreciate if you could post an answer that clears my understanding about the problem. I found on the internet that finding number of children gets you to the answer, but why ? – Rohan Kumar Sep 27 '16 at 17:10
  • ok, I will post my own understanding of my accepted solution, and my accepted code as an answer – shole Sep 28 '16 at 01:12

1 Answers1

1

First of all, the question said all test cases (all input trees), there exists a way to remove edges so that the even size of the forest is preserved. And of course as every tree in the result forest is of even size, that means the total number of nodes N must be even. Even tree must have solution as at least they can remove 0 edge to form a even forests.

Notice that there are some edges CANNOT be removed, namely, the edge connecting the leaf nodes. Therefore some greedy thoughts pop up in my head, and turns out I can proof them, so they become the greedy algorithm which can solved the problem.


I claim that

a) Any subtree of even size, we can safely remove them from the original graph to reduce the problem without affecting the result, by removing the edge of the subtree root and its parent (if exist)

b) Any subtree of odd size, we can replace whole subtree with a single node to reduce the problem. The edge of the subtree root and its parent CANNOT be removed (if exist)

We proof a) by contradiction. Assume if we remove the even subtree for the graph will make the problem from solvable to unsolvable. Consider the graph after removing the even subtree, if it is of odd size, then the original graph is unsolvable as well; if it is of even size, then it must have solution after removing the even subtree. Both cases yield contradiction.

b) is quite straight forward, as the subtree is odd size, its parity is the same as a single leaf node, which must be connected with its parent. So we can replace the subtree by a single node to reduce the problem.


By a) and b), we can do a greedy algorithm from the leafs of the tree (because we already know the edges connecting the leafs must be chosen, they are forming subtrees and we can reduce the problem starting from here)

  1. Connect all leafs with their parents
  2. For all subtrees formed, if the subtree is even, add the global answer counter by 1 and remove the subtree; if the subtree is odd, replace it as a single node (which is also leaf now).
  3. Repeat 2 until at most 1 node is left

That's it. Conceptwise, this is the algorithm.

You can implement it using many different methods though, I use DFS which is quite directly translating this algorithm to code.

Some simply count the number of children because this can tell if the subtree is odd or even.

Someone even only count the # of nodes which has even degrees! (This is by far the smartest solution I know)

But all of them share the same concept behind: Determine if the subtree is odd size of even size, remove them (and increase the answer counter) or replace them by a single node to reduce the problem.

All implementation share same complexity O(N) as well.

Here is my accepted code:

#include<bits/stdc++.h>
using namespace std;

int w[105][105] = {0}, v[105] = {0};
int n,m,ans=0;

int dfs(int x){
    v[x] = 1;
    int son = 0;
    for(int i=0; i<105;i++) 
        if(w[x][i] && !v[i]) son += dfs(i);
    if(son % 2) { ans++; return 0;}
    return 1;
}

int main() {
    scanf("%d%d", &n,&m);
    for(int i=0,a,b; i<m;i++){
        scanf("%d%d", &a,&b);
        w[a][b] = w[b][a] = 1;
    }
    dfs(1);
    printf("%d\n", ans-1);  
    return 0;
}
shole
  • 4,046
  • 2
  • 29
  • 69