k-center

Chooses k centers so that the vertex farthest from its nearest center is as near as it can make it.

Time complexity O(k (V+E) log V), gograph function path.KCenter.

How it works

Where should a company open k warehouses so that no address is a long drive from all of them? Trying every choice is far too slow on a city, so path.KCenter chooses them farthest first: it opens the first warehouse, then keeps opening the next one at the address farthest from every warehouse so far. Each new warehouse needs a search only over the addresses it gets closer to, and k rounds cost O(k (V+E) log V).

When every road works both ways in the same time, the longest drive this leaves is never more than twice the best any k warehouses can do. With one-way streets the drives aren't symmetric, and that factor of two isn't guaranteed.

The second warehouse often lands at the edge of the map. The method shrinks the worst drive, so it serves the most remote address first. That is the difference from k-median, which minimizes the average drive and puts warehouses nearer the busy middle.

Warehouses that are already open can be passed as fixed centers. They count toward k and open first, in the order given. Without them, the first center is the first vertex added to the graph. Which one opens first changes the rest.

London streets

The main roads of central London from Westminster to the City, from OpenStreetMap, with the bridges over the Thames to Southwark and Waterloo. Each intersection is named after its streets, one-way streets go one way, and each edge is the minutes to drive it at the speed limit, or at 20 to 32 km/h by road type where the map has no limit.

A directed, weighted graph with 274 vertices and 598 edges.

Map data © OpenStreetMap contributors.

With one warehouse at Trafalgar Sq & Strand, where should three more open so that the longest drive to any intersection is as short as it can be made?

Open warehouses at Trafalgar Sq & Strand, Commercial St & Fleur De Lis St, Southwark Park Rd & St James's Rd and Kennington Lane & Cottington St, in that order. The longest drive is 6.09.

Step by step

  1. No warehouse is open yet, so every drive time starts at ∞.
  2. Open warehouse 1 at Trafalgar Sq & Strand, which is given. A search from it gives every place it reaches a drive time. The search goes on to St Martin's Pl & Charing Cross Rd and Trafalgar Sq & Charing Cross.
  3. Take Trafalgar Sq & Charing Cross from the queue. Warehouse 1 reaches it in 0.12, and nothing reaches it sooner. The search goes on to Northumberland Ave & Victoria Embankment, Parliament Sq & Great George St and Trafalgar Sq & Cockspur St.
  4. Take Trafalgar Sq & Cockspur St from the queue. Warehouse 1 reaches it in 0.3, and nothing reaches it sooner. The search goes on to Cockspur St near Warwick House St and Trafalgar Sq near Cockspur St.
  5. Take Trafalgar Sq near Cockspur St from the queue. Warehouse 1 reaches it in 0.35, and nothing reaches it sooner. It has no neighbor left to check.
  6. Take St Martin's Pl & Charing Cross Rd from the queue. Warehouse 1 reaches it in 0.37, and nothing reaches it sooner. The search goes on to Charing Cross Rd & Shaftesbury Ave and St Martin's Lane & St Martin's Pl.

449 more steps lead to the last one:

  1. Warehouse 4's search is done. 44 places moved to it. 4 warehouses are open. The farthest place from every warehouse is Goswell Rd near Glasshouse Yard, 6.09 from warehouse 2, so the longest drive is 6.09. There are 229,741,876 ways to choose 4 of the 274 places, too many to try. Some roads here are one way, so the factor of two isn't guaranteed.

Use it in Go

centers, longest, err := path.KCenter(g, 4, "Trafalgar Sq & Strand")
if err != nil {
	return err
}
for _, v := range centers {
	fmt.Println(v.Label())
}
fmt.Println(longest)

Example graphs

More in Shortest paths

  • Dijkstra: Finds the shortest distance from a start vertex to every other vertex when no edge weight is negative.
  • Multi-source Dijkstra: Finds the nearest of several sources for every vertex, and the distance from it, in one search.
  • Bellman-Ford: Finds the shortest distance from a start vertex to every other vertex, even with negative weights, and reports a negative cycle when the start can reach one.
  • Floyd-Warshall: Finds the shortest distance between every pair of vertices, even with negative weights, by letting paths stop at one more vertex in each round.

All algorithms