Google Code Jam 2014: Full Binary Tree
Oke I'm going to have with this review the point of javadoc, namings and methods.

First :

You make comment, what is actually good but try to make javadoc in stead of commenting everything.

// comparator for sorting only
class NodeComparator implements Comparator&lt;Node&gt; {
    @Override
    public int compare(Node n0, Node n1) {
        return n0.getNDescendants() - n1.getNDescendants();
    }    
}


should be :

/**
* Comparator for sorting on descendants
*/
class NodeComparatorNDescendants implements Comparator&lt;Node&gt; {
    @Override
    public int compare(Node n0, Node n1) {
        return n0.getNDescendants() - n1.getNDescendants();
    }    
}


Why :
This cause you no more effort than commenting, but you can generate a complete javadoc what other persons can look into.
Also see that I added the on what you are sorting there.
At last I changed also the class name. Now you will already see without the javadoc on what you will compare.
Note : Effective class name helps you later also, take this code after a year not seen and you will need to see the implementation of the comparator if you want to know on what it compares.

Second :

Like I already said in the first point, naming is everything. 
Node n => why just not Node node.
Other example : NodeComparator cmp => NodeComparator nodeComparator
This will not take more memory from your program if you have fear for that :), and if you use autocomplete this will not lose time to program.

Thirth :

Small effective methods are better than big ones that do a lot.
How less code in a method => the sooner you find the bug because your method complexity is lower.

Example :

// turns the tree into a full binary tree by removing as few nodes as possible
public void makeFullBinary() {
    // first, recursively make all the children into full binary trees
    for (Node n : children) {
        n.makeFullBinary();            
    }
    // sort the children from least to most number of descendants
    Collections.sort(children, cmp);
    // remove descendants as needed to end up with 0 or 2
    while ((children.size() != 0) &amp;&amp; (children.size() != 2)) {
        children.remove(0);
    }
    // recompute the number of descendants
    nDescendants = 0;
    for (Node c : children) {
        nDescendants += 1 + c.getNDescendants();
    }
}


should be :

// turns the tree into a full binary tree by removing as few nodes as possible
public void makeFullBinary() {

    createBinaryTree();
    Collections.sort(children, cmp);
    adjustBinaryTree();
    recalculateDescendants();
}

private void createBinaryTree () {
    for (Node n : children) {
        n.makeFullBinary();
    }
}

private void adjustBinaryTree () {
    while ((children.size() != 0) &amp;&amp; (children.size() != 2)) {
        children.remove(0);
    }
}

private void recalculateDescendants () {
    nDescendants = 0;
    for (Node c : children) {
        nDescendants += 1 + c.getNDescendants();
    }
}


Why :
Each method is shorter then the whole method.
It's easier to read and to comprehent the actual doing of the method.
Now there is just one thing what bothers me, but it is an discussion amoung programmers, that's the reason I didn't changed it but still going to say
nDescendants is a calculated field.
For more rightness you should remove the int and set the recalculateDescendants code in the getNDescendants().
Yes you lose performance and you gain an always correctness of the getter.
Now you see directly why there are always discussions about that.

Hope this helps you already to improve yourself.