User:Jeff/Simplified GSM Network

Analysis
There are two aspects to this algorithm. For each road in the map, we first need to calculate how many cell boundaries it crosses. We then use this information to solve a series of point-to-point shortest path problems.

Finding the cost of a road
This is a graph theory problem, where the cities are nodes in the graph and the roads are edges. The weight, or cost, of each road is equal to the number of cell boundaries it intersects. We could find this number using a lot of advanced geometry, or we could use a simple recursive approach. All we need are a couple of helper functions: one to find the squared distance between two points, and one to find the closest tower to a given point.

typedef pair p2d; double dist2(p2d &a, p2d &b) { return (a.X - b.X) * (a.X - b.X) + (a.Y - b.Y) * (a.Y - b.Y); } int closestTower(vector &towers, vector &p) { double minDist(INF), ans(0); for (int i(0); i < towers.size; ++i) { if (minDist < dist2(towers[i], p)) continue; minDist = dist2(towers[i], p); ans = i; } return ans; }
 * 1) define X first
 * 2) define Y second

To program the recursive function, there are three cases to consider. First, if the two cities share the same closest tower, then they are inside the same cell; no boundaries will be crossed while driving from cityA to cityB. Otherwise, if the two cities are so close to each other that they are practically the same point, but they still have two different closest providers, then there must be exactly one cell boundary separating them. The third case, when the cities are a normal distance apart but have different closest towers, is the recursive case. Find the midpoint of the line segment connecting the two cities, and sum the distances from the midpoint to each city.

int roadCost(vector &towers, p2d &cityA, p2d &cityB) { if (closestTower(towers, cityA) == closestTower(towers, cityB)) return 0; // the two cities are inside the same cell boundary if (dist2(cityA, cityB) < EPSILON) return 1; // one cell boundary separates the cities p2d mid((cityA.X + cityB.X) / 2, (cityA.Y + cityB.Y) / 2); return roadCost(towers, cityA, mid) + roadCost(towers, mid, cityB); }
 * 1) define EPSILON 1e-9

Dijkstra's algorithm
Once we have calculated a cost for each road, the problem is reduced to finding the shortest path in an undirected, weighted graph. The best way to do this is with a modified Dijkstra's algorithm. We'll wrap the algorithm in a class, and use a separate instantiation for each query in the input.

typedef pair p2i; struct Dijkstra { map cost; set queue; int city; Dijkstra(int start) { cost[start] = 0; queue.insert(p2i(0, start)); }  p2i pop { city = queue.begin->Y; queue.erase(queue.begin); return city; }  int distance { return cost[city]; }  void push(int dest, int weight) { weight += distance; if (cost.find(dest) == cost.end) { cost[dest] = weight; queue.insert(p2i(weight, dest)); return; }    if (cost[dest] <= weight) return; queue.erase(p2i(cost[dest], dest)); cost[dest] = weight; queue.insert(p2i(weight, dest)); } };