Hints for SRM 680, D1, 500-Pointer (BearSpans)

James S. Plank

Tue Feb 16 18:18:51 EST 2016
Problem Statement.
That's a neat algorithm. It works because it takes at most log(n) steps where n is the number of nodes.

Let's motivate our solution with some examples. Suppose n = 5, m = 10 and k = 1. Then any solution that contains the following graph will work (oh, I'm going to number my nodes from 0 to n-1, and then convert 0 to n at the end. It makes life easier.)

Now, suppose instead that n = 5, m = 10 and k = 2. Then any solution that contains the following graph will work:

Those are two extreme cases, and they form the basis for our answer. We'll work in rounds, and instead of dealing with individual nodes, we'll deal with connected components. We are going to add edges to our system in increasing order of weight. When we're done, if we have edges leftover, we'll simply add them randomly to any pair of nodes that don't have edges already.

If our round number is equal to k, then we connect the components as in the first example above. That way, Boruvka's algorithm will complete in that step.

If the round number is less than k, then we try to delay the completion of the algorithm as much as we can. We can do that by reducing the number of components by a factor of two: For each even number i we add an edge from component i to component i+1.

If we end up with one component and k is still greater than the round number, then it is impossible, and we return { -1 }.

Here's an example. Suppose n=18, m=22 and k=3. Here is what the graph looks like after round 1:

And round 2:

We need to finish up in round three, so we connect all of the components with edges in consecutive order:

Finally, we need to add 5 random edges to the system, so we do so, and we rename node 0 to node 18. We're done!

Three comments with respect to implementing this:

  1. Numbering from zero makes life easier, because a representative node from component i in round j may be calculated very simply with node i << j (rounds are zero indexed here too).

  2. I found it easier mentally, when I had an odd number of components and I wasn't in the last round, to add the unmatched component to the last component. For example, in the picture above in round 2 (the one where I added edges 10 through 13 to the graph), I would also add an edge with a weight of 14 from node 16 to node 12. It doesn't really matter, but it made it easier for me to think about.

  3. To add the edges at the end, I had a vector that had an entry for every pair of nodes (it was a 2D vector). Whenever I added an edge to the graph, I'd mark it in the vector. That way, at the end, I could simply run through the vector and add edges to unconnected pairs of nodes. Yes, the size of that vector is O(n2), but with n being 1000, that's ok.