bigintegers's blog

By bigintegers, history, 4 years ago, In English

Given N points representing the coordinates of heroes on the coordinate plane and another N points representing the coordinates of enemies on the coordinate plane, each hero plans to battle a single enemy (the number of enemies equals the number of heroes, so nobody is ever left out).

Each hero prioritizes the enemy that is closest to them, where distance is defined as taxicab (orthogonal) distance as opposed to Euclidean distance. For example, if we have two points p, q, then the distance is NOT sqrt((p.x — q.x)^2 * (p.y — q.y)^2) but instead |p.x — q.x| + |p.y + q.y|. No two pairs of heroes and enemies will have the same distance.

What's an efficient way to make the matching? I thought about lots of graph algorithms but cannot come up with much. Maybe something with a priority queue/heap?

Thank you

  • Vote: I like it
  • +5
  • Vote: I do not like it

| Write comment?
»
4 years ago, # |
Rev. 2   Vote: I like it 0 Vote: I do not like it

Is it possible for a hero to have multiple enemies of minimum distance? The condition "No two pairs of heroes and enemies will have the same distance" does not necessarily imply this, unless I'm misinterpreting it. For example, two heroes at $$$(0, 0)$$$ and $$$(0, 2)$$$ and two enemies at $$$(0, 1)$$$ and $$$(0, 3)$$$.

Also, do you have a source for this problem?

  • »
    »
    4 years ago, # ^ |
      Vote: I like it 0 Vote: I do not like it

    This is a problem motivated by myself after I learned about bipartite matching and Hall's theorem on my own (but I don't think bipartite matching is the correct solution here?).

    I guess what I meant to say regarding the distances is that they will all be different. So there is no ambiguity.

    • »
      »
      »
      4 years ago, # ^ |
      Rev. 2   Vote: I like it 0 Vote: I do not like it

      Bipartite matching is not really necessary, although there might be some elegant solution with good complexity. I'll outline an $$$O(nlog^2)$$$ since I don't know how to do better.

      First, we're going to exploit the distance metric. Let's imagine a naive solution where we, for each hero, iterate through the distance from 0 to infinity until we find the first enemy in our hero's range. This can be improved by binary search, but we do no better than $$$O(n^2log)$$$. Because of the taxicab metric, our hero's range will look like a diamond centered around the hero:

      1

      Diamonds are difficult to work with. What about squares? If we rotate the $$$OXY$$$ axis by 45 degrees (by replacing each point $$$(x, y)$$$ with $$$(x + y, x - y)$$$, then we get something like this:

      2

      Now we want, for each hero, the smallest square with its center at the hero that has exactly one enemy within it. Because there is no ambiguity in the distances, this must exist for each hero. One way to do this in $$$O(nlog^3n)$$$ is by binary searching on a 2D implicit segment tree, but that's basically no better than $$$O(n^2)$$$. Another way is more smoother but uses a similar approach.

      Compress the x-coordinates, but maintain the positions of each of them. This is so we can use a segment tree for range maximum queries. We will do a line sweep on the y-coordinate and find the answer for each hero sequentially. Start a line at the hero at the highest y-coordinate and go down. We need two segment trees for this, one for enemies below and one for enemies above our current hero. The entries in the segment trees represent the y-distance from our current hero. Initially, all enemies below the top hero can be inserted into our 'below' tree position $$$x_{enemy}$$$ with value $$$y_{hero} - y_{enemy}$$$, and all enemies above the top hero are inserted into our 'above' tree into position $$$x_{enemy}$$$ with value $$$y_{enemy} - y_{hero}$$$

      Now the RMQ value for an x-coordinate range for the above/below tree represents the minimum y-distance in the range. What this means is, for a given x-range, we can find if a point is in the square with vertical sides at those x-coordinates. Treating the above and below trees separately (we just take the minimum of their two answers), we now want the smallest possible square that satisfies that the minimum difference in y-value <= the size of the x-range, meaning that there is at least one point in the range. If this square was any smaller, there would be no points in it. We can binary search on this, decreasing our square size when the RMQ value for our range is less than the x-range and increasing when it's not true. Our x-coordinates (the compressed ones that we use for the segment tree) can be found with another binary search (it's just another $$$logn$$$ factor). Note that it is not difficult to recover the coordinates after doing this, which will give the actual enemy we use.

      Now we need to make changes to the trees when we switch between heroes. First, we shift all of the y-coordinates of the enemies by how much we go down from our last hero to our current one. The easiest way to do this is with lazy propagation, there's a better way but this comment is way too long already. Then we remove all enemies in the below tree that are now above our current hero and insert them into the above tree. Doing this process for each hero, we have an $$$O(nlog^2)$$$ ($$$O(n)$$$ heroes, $$$O(log)$$$ for binary search, $$$(O(logn)$$$ for the segment tree) solution.

      tl;dr: rotate the grid 45 degrees, line sweep, binary search on RMQ

      Please ask if anything's unclear. It probably is.

»
4 years ago, # |
  Vote: I like it 0 Vote: I do not like it

It’s not clear from the statement if you want to minimize the sum of the distances or the max distance.