Friday, August 18th

 Network Ranks

Given a collection of roads connecting cities, calculate the maximal network rank of the infrastructure, with network rank defined as the total number of incoming roads between the two cities, where roads connecting the two cities are only counted once

The Pregel river running through Koenigsberg

This is obviously a graph problem.  My first approach was way too complicated, involving calculating the cities with the highest degree.  However, with only a maximum of 100 cities, it is possible to brute force the problem and calculate the network rank for every pair of cities.

To do so, first first convert the roads list into an adjacency list.  Then for every pair, calculate the 2 degrees for the cities.  Finally, check if the city pair contain an edge between them, and if so, deduct the degree total by 1.  Maintain the highest network rank and return the solution.

The following code converts the edgelist to an adjacency list of size n

    vector<vector<int> >adjlist(n);
int n1,n2;
for(int i=0; i<roads.size(); i++) {
n1=roads[i][0];
n2=roads[i][1];
adjlist[n1].push_back(n2);
adjlist[n2].push_back(n1);
}

Now to calculate the network rank, we iterate over all possible city combinations. Keep a tmp result that stores the network rank before testing for an edge between the two cities, and a res variable to store the final result.  A city's network rank is the size of its entry in the adjacency list, so tmp is the size of each city's entry in the adjacency list.

    int tmp; //temp result pre-shared edge
int res=0; //final network result
bool shared_edge; //
for(int i=0; i<n-1; i++) {
for(int j=i+1; j<n; j++) {
shared_edge=false;
tmp = adjlist[i].size() + adjlist[j].size();
            ...
        }
    }

Now we have the temporary rank, but need to find out if there is a road connecting the two cities.  We can iterate through the adjacency list of 1 city and look for the existence of the other city.

One way to accomplish this is through a simple scan through the whole adjacency list array.  If the edge is found, mark the shared_edge boolean as true, which will trigger a reduction of the network rank by 1.

    for(int k=0; k<adjlist[i].size(); k++) {
    if(adjlist[i][k]==j) {
    shared_edge=true;
break;
}
}
if(shared_edge) tmp--;
res=max(res,tmp);

Finally, we return res as the final maximal rank

    return res;

In the above approach, a shared edge is detected by a linear scan through all adjacent nodes.  While it is simpler and still meets runtime requirements, this can be improved.  Instead of a linear scan, we pre-sort each adjacency list, then perform a binary search through the adjacency list.  Fortunately, C++ has functions for the two operations required to accomplish this approach.

First we sort each entry in the adjlist

    for(int i=0; i<adjlist.size(); i++) {
        sort(adjlist[i].begin(), adjlist[i].end());
    }

Then, instead of a linear scan, we perform binary search.  And if a successful search is detected, then we deduct the temporary rank by 1.  Finally, 

    int ind=lower_bound(adjlist[i].begin(),adjlist[i].end(), j)-adjlist[i].begin();
    if( ind!=adjlist[i].size() ) {
         if(adjlist[i][ind]==j)tmp--;
    }
    res=max(res,tmp);

While the linear scan is easier to implement, the binary search technique uses 2 built-in C++ functions and outperforms by linear scan by 30%.



Thanks to the Editorial for showing that brute force is acceptable


Comments

Popular posts from this blog

Wednesday, September 20th

Monday, September 11th

Tuesday, September 19th