LOJ 1002 - Country Roads
Tags : graph, single source shortest path
We will be given information of an area map (undirected graph / bi-directional graph) through the number of cities (nodes),number of roads (edges) in total and the cost (weight) for each pair of linked cities via the road. And we will also be given t the home town (the staring node) and we have to print out the minimum cost to reach this town from other cities.
Helpful Resources
Solution
At first we will simply create a graph structure for the Area Map in any preferred method (adj. matrix/ linked list). The problem statement has confirmed : (1) there shall be no negative cost for the roads and (2) the graph is a bi-directional/undirected graph. We can apply Dijsktra's Algorihtm or its derivative or any similar. But we must keep in mind that we are finding many dedicated optimal paths(one path per one city), not one optimal path to traverse all the cities in 1 go. For each individual city's optimal path, we take the minimum from all the path's costs. Here, a path's cost = maximum weighted road encountered which we will be saving in a separate array/list.
We at first update the cost if the two cities have directly connected edges among them, and in that case we will only keep the lowest possible weight. It's a duplicate we get rid off while taking inputs for edges. Let's look at the Case 2
's inputs':
5 4
0 1 5
0 1 4
2 1 3
3 4 7
1
In this case, 0 1 5
and 0 1 4
are inputs for 0 -- 1
edge along with the weight/cost. We will update
while taking inputs
and update from cost[0,1] = 5
to cost[0,1] = 4
as it is minimum among those two directly connected edges.
Now we need to traverse and update costs. We will take another graph example to discuss how we are traversing. We will go full brute force by not leaving any route for a home town to another city untried. For example:
All the possible paths for 1 to 2
:
Route |
Max Road Cost |
Update |
1 -- 0 -- 3 -- 4 -- 2 |
8 |
From infinity to 8 |
1 -- 4 -- 3 -- 0 -- 2 |
9 |
No |
1 -- 0 -- 2 |
9 |
No |
1 -- 4 -- 2 |
7 |
From 8 to 7 |
This is how we are traversing, leaving no path untried. We just update the distance array/list for [1,2] = 7
as it is the minimum. We are only updating the cost of the destination. We repeat this process for from home town to all the other cities and ultimately get the distance array/list.
What would happen if we had marked to avoid repetition so that we find just one single optimal path to travel them all in 1 go?
Current City |
Visited |
Next City (City with lower cost) |
Update |
Highest Road Cost |
1 |
{} |
0 |
[1,0] = 2 |
2 |
0 |
{0} |
3 |
[1,3] = 6 |
6 |
3 |
{0,3} |
4 |
[1,4] = 8 |
8 |
4 |
{0,3,4} |
2 |
[1,2] = 8 |
8 |
2 |
{0,3,4,2} |
All City Traversed |
N/A |
8 |
We have constructed a single optimal path, but the only thing wrong here is [1,2] = 8
which is the wrong answer. Thus we are not to use any algorithm that re-maps the whole area or does not check all possible routes in a brute force manner.
Caution : Remember to use fast I/O for your preferred language as per the suggestion from the problem statement and find out what may disrupt them to avoid it.
The above implementation is accepted
.
Solution in C++
#include <bits/stdc++.h>
using namespace std;
int main()
{
ios::sync_with_stdio(false);
cin.tie(NULL);
cout.tie(NULL);
int testCases, numberOfCities, numberOfRoads,
sourceCity, destinationCity, roadCost, homeTown, maxCostFound;
cin >> testCases;
for (int i = 1; i <= testCases; i++)
{
cin >> numberOfCities >> numberOfRoads;
vector<int> areaMap[numberOfCities];
int distanceFromHomeTown[numberOfCities];
int cost[numberOfCities][numberOfCities];
memset(cost, 0, sizeof(cost));
for (int i = 0; i <= numberOfCities; i++)
distanceFromHomeTown[i] = INT_MAX;
for (int i = 0; i < numberOfRoads; i++)
{
cin >> sourceCity >> destinationCity >> roadCost;
if (cost[sourceCity][destinationCity])
{
cost[sourceCity][destinationCity] = cost[destinationCity][sourceCity] = min(cost[sourceCity][destinationCity], roadCost);
}
else
{
areaMap[sourceCity].push_back(destinationCity);
areaMap[destinationCity].push_back(sourceCity);
cost[sourceCity][destinationCity] = cost[destinationCity][sourceCity] = roadCost;
}
}
cin >> homeTown;
queue<int> cityQueue;
cityQueue.push(homeTown);
distanceFromHomeTown[homeTown] = 0;
while (!cityQueue.empty())
{
int startingCity = cityQueue.front();
cityQueue.pop();
for (int i = 0; i < areaMap[startingCity].size(); i++)
{
int currentCity = areaMap[startingCity][i];
maxCostFound = max(distanceFromHomeTown[startingCity],
cost[startingCity][currentCity]);
if (distanceFromHomeTown[currentCity] > maxCostFound)
{
distanceFromHomeTown[currentCity] = maxCostFound;
cityQueue.push(currentCity);
}
}
}
cout << "Case " << i << ":\n";
for (int i = 0; i < numberOfCities; i++)
if (distanceFromHomeTown[i] == INT_MAX)
cout << "Impossible\n";
else
cout << distanceFromHomeTown[i] << "\n";
}
return 0;
}
Tutorial source