minimum number of days to reach destination | graph - algorithm

Given a graph in which each node represents a city. Some cities are connected to each other through bidirectional roads. The length of each road is also given. Some of the cities have hotels. Given a start city and a destination city and a value K which represents the maximum distance that can be travelled by a person in one day, find the minimum number of days in which the person can reach his destination (or tell if it is impossible for the given K).
(Note : If the distance travelled in one day is exceeding K, the person can rest in the city which has a hotel in it, if there is no hotel in that city this implies you have to choose another path. Next day, the person can start from that city and the distance travelled get reset to 0).

This can be done with Dijkstra:
lets say our dijkstra state is {daysPassed, timeTravelled, vertexId}
initial state is {0,0,startCity} we add it to priority queue (sorted as tuples, min first)
For each state in queue:
try going to all neighboring cities (if timeTravelled + edgeWeigth <= maxTravelTimePerDay), state changes to {daysPassed, timeTravelled + edgeWeight, neighbourId}
try to sleep in current city (if it has a hotel), state changes to {daysPassed + 1, 0, vertexId}
Of course its not profitable to sleep in same hotel 2 times so we can additionally keep a boolean array indicating whether we slept in some hotel and only try to sleep in hotel once (on first time visiting vertex)
if any time during algorithm we reach goal city daysPassed from state is the answer

Related

Minimal car refills on a graph of cities

There's a graph of cities.
n - cities count
m - two-ways roads count
k - distance that car can go after refill
Road i connects cities pi and qi and has length of ri. Between the two cities can be only one road.
A man is going from city u to city v.
There are a gas stations in l cities a1, a2, ..., al.
A car starts with a full tank. If a man gets in a city with a gas station, he can refill (full tank) a car or ignore it.
Return value is a minimal count of refills to get from a city u to city v or -1 if it's impossible.
I tried to do it using Dijkstra algorithm, so I have minimal distance and path. But I have no idea how to get minimal refills count
It is slightly subtle, but the following pseudo-code will do it.
First do a breadth-first search from v to find the distance from every city to the target. This gives us a distance_remaining lookup with distance_remaining[city] being the shortest path (without regards to fillup stations).
To implement we first need a Visit data structure with information about visiting a city on a trip. What fields do we need?
city
fillups
range
last_visit
Next we need a priority queue (just like Dijkstraa) for possible visits to consider. This queue should prioritize visits by the shortest possible overall trip that we might be able to take. Which is to say visit.fillups * max_range + (max_range - visit.range) + distance_remaining[visit.city].
And finally we need a visited[city] data structure saying whether a city is visited. In Dijkstra we only consider a node if it was not yet visited. We need to tweak that to only consider a node if it was not yet visited or was visited with a range shorter than our current one (a car that arrived on full may finish even though the empty one failed).
And now we implement the following logic:
make visit {city: u, fillups: 0, range: max_range, last_visit: None}
add to priority queue the visit we just created
while v = queue.pop():
if v.city == u:
return v.fillups # We could actually find the path at this point!
else if v not in visited or visited[v.city] < v.range:
for each road r from v.city:
if r.length < v.range:
add to queue {city: r.other_city, fillups: v.fillups, range:v.range - r.length, last_visit: v}
if v.city has fillup station:
add to queue {city: v.city, fillups: fillups + 1, range: max_range, last_visit: v}
return -1

Minimum cost to visit museum

I recently went for an hiring challenge and saw this question :
Given map of N museums with given entry fees and M weighted bidirectional roads connecting them. Starting from each museum, we need to find minimum cost to visit at least one museum. The cost will be an addition of sum of weights of roads travelled and visited museum entry fee.
Input format :
Number of museums N and number of roads M
Entry fees of each museum
Next M lines will have x, y, z where museum x and museum y are connected by road with weight z
Output Format :
N integers where ith integer denotes minimum cost to reach and enter any museum starting from ith museum.
Input :
5 4
1 2 3 1 5
1 2 1
2 3 1
3 4 1
4 5 1
Output :
1 2 2 1 2
Here, starting from museum 1, we can directly visit museum 1 with entry fee of 1.
Starting from museum 3, we can visit museum 4 with cost of 2.
I need optimized approach efficient than applying dijsktra from each node of graph. Constraints are high enogh to avoid floyd warshall algorithm.
Thanks in advance.
Your graph starts off with nodes of "outside Museum X" and edges roads between them.
You need a priority queue of entries that look like this:
{
cost: xxx,
outside_museum: xxx
}
You initialize it with entries that look like this:
{
cost: entry_fee_for_museum_x,
outside_museum: x
}
Keep a dictionary mapping museum to lowest cost named something like cost_to_museum.
And now your loop looks like this:
while queue not empty:
get lowest cost item from queue
if it's museum is not in cost_to_museum:
cost_to_museum[item.outside_museum] = item.cost
for each road connecting to museum:
add to queue an entry for traveling to here from there
(That is, location is the other museum, cost is road + current cost)
This should execute in time O((n+m) log(n+m)) where n is the number of museums and m is the number of roads.

Maximum profit earned in Interval

We have to rent our car to customers. We have a list whose each element represent the time at which car will be given, second -> the time at which car will be returned and third -> the profit earned at that lending. So i need to find out the maximum profit that can be earned.
Eg:
( [1,2,20], [3,6,15], [2,8,25], [7,12,18], [13,31,22] )
The maximum profit earned is 75. [1,2] + [3,6] + [7,12] + [13,31].
We can have overlapping intervals. We need to select such case that maximizes our profit.
Assuming you have only one car, then the problem we are solving in Weighted Interval Scheduling
Let us assume we have intervals I0 , I1, I2, ....In-1 and Interval Ii is (si,ti,pi)
Algorithm :
First sort the Intervals on the basis of starting points si.
Create a array for Dynamic Programming, MaxProfit[i] represent the maximum profit you can make from intervals Ii,Ii+1,In-1.Initialise the last value
MaxProfit[n-1] = profit_of_(n-1)
Then using DP we can find the maximum profit as :
a. Either we can ignore the given interval, In this case our maximum profit will be the maximum profit we can gain from the remaining intervals
MaxProfit[i+1]
b. Or we can include this interval, In this case the maximum profit can be written as
profit_of_i + MaxProfit[r]
where r is the next Interval such that sr > ti
So our overall DP becomes
MaxProfit[i] = max{MaxProfit[i+1], profit_of_i + MaxProfit[r] }
Return the value of MaxProfit[0]
use something like dynamic programming.
at first sort with first element.
you have 2 rows, first show most earned if this time is used and another is for most earned if not used.
then you will put each task in the related period of time and see in each time part it is a good choice to have it or not.
take care that if intervals are legal we choose all of them.

rudimentary flight trip planner

![question based on travel planner][1]
what approach will be best for solving this problem?,any kind of help will be appreciated
The input is the set of flights between various cities. It is given as a file. Each line of the file contains "city1 city2 departure-time arrival-time flight-no. price" This means that there is a flight called "flight-no" (which is a string of the form XY012) from city1 to city2 which leaves city1 at time "departure-time" and arrives city2 at time "arrival-time". Further the price of this flight is "price" which is a poitive integer. All times are given as a string of 4 digits in the 24hr format e.g. 1135, 0245, 2210. Assume that all city names are integers between 1 and a number N (where N is the total number of cities).
Note that there could be multiple flights between two cities (at different times).
The query that you have to answer is: given two cities "A" and "B", times "t1", "t2", where t1 < t2, find the cheapest trip which leaves city "A" after time "t1" and arrives at city "B" before time "t2". A trip is a sequence of flights which starts at A after time t1 and ends at B before time t2. Further, the departure time from any transit (intermediate) city C is at least 30 mins after the arrival at C
You can solve this problem with a graph search algorithm, such as Dijkstra's Algorithm.
The vertices of the graph are tuples of locations and (arrival) times. The edges are a combination of a layover (of at least 30 minutes) and an outgoing flight. The only difficulty is marking the vertices we've visited already (the "closed" list), since arriving in an airport at a given time shouldn't prevent consideration of flights into that airport that arrive earlier. My suggestion is to mark the departing flights we've already considered, rather than marking the airports.
Here's a quick implementation in Python. I assume that you've already parsed the flight data into a dictionary that maps from the departing airport name to a list of 5-tuples containing flight info ((flight_number, cost, destination_airport, departure_time, arrival_time)):
from heapq import heappush, heappop
from datetime import timedelta
def find_cheapest_route(flight_dict, start, start_time, target, target_time):
queue = [] # a min-heap based priority queue
taken_flights = set() # flights that have already been considered
heappush(queue, (0, start, start_time - timedelta(minutes=30), [])) # start state
while queue: # search loop
cost_so_far, location, time, route = heappop(queue) # pop the cheapest route
if location == target and time <= target_time: # see if we've found a solution
return route, cost
earliest_departure = time + timedelta(minutes=30) # minimum layover
for (flight_number, flight_cost, flight_dest, # loop on outgoing flights
flight_departure_time, flight_arrival_time) in flight_dict[location]:
if (flight_departure_time >= earliest_departure and # check flight
flight_arrival_time <= target_time and
flight_number not in taken_flights):
queue.heappush(queue, (cost_so_far + flight_cost, # add it to heap
flight_dest, flight_arrival_time,
route + [flight_number]))
taken_flights.add(flight_number) # and to the set of seen flights
# if we got here, there's no timely route to the destination
return None, None # or raise an exception
If you don't care about efficiency, you can solve the problem like this:
For each "final leg" flight arriving at the destination before t2, determine the departure city of the flight (cityX) and the departure time of the flight (tX). Subtract 30 minutes from the departure time (tX-30). Then recursively find the cheapest trip from start, departing after t1, arriving in cityX before tX-30. Add the cost of that trip to the cost of the final leg to determine the total cost of the trip. The minimum over all those trips is the flight you want.
There is perhaps a more efficient dynamic programming approach, but I might start with the above (which is very easy to code recursively).

Neo4J - Traveling Salesman

I'm trying to solve an augmented TSP problem using a graph database, but I'm struggling. I'm great with SQL, but am a total noob on cypher. I've created a simple graph with cities (nodes) and flights (relationships).
THE SETUP: Travel to 8 different cities (1 city per week, no duplicates) with the lowest total flight cost. I'm trying to solve an optimal path to minimize the cost of the flights, which changes each week.
Here is a file on pastebin containing my nodes & relationships. Just run it against Neo4JShell to insert the data.
I started off using this article as a basis but it doesn't handle the changing distances (or in my case flight costs)
I know this is syntactically terrible/non-executable, but here's what I've done so far to get just two flights;
MATCH (a:CITY)-[F1:FLIGHT{week:1}]->(b:CITY) -[F2:FLIGHT{week:2}]->(c:CITY)
RETURN a,b,c;
But that doesn't run.
Next, I thought I'd just try to find all the cities & flights from week one, but it's not working right either as I get flights where week <> 1 as well as =1
MATCH (n) WHERE (n)-[:FLIGHT { week:1 }]->() RETURN n
Can anyone help out?
PS - I'm not married to using a graph DB to solve this, I've just read about them, and thought it would be well fitted to try it, plus gave me a reason to work with them, but so far, I'm not having much (or any) success.
Maybe this Cypher query will give you some ideas.
MATCH (from:Node {name: "Source node" })
MATCH path = (from)-[:CONNECTED_TO*6]->()
WHERE ALL(n in nodes(path) WHERE 1 = length(filter(m in nodes(path) WHERE m = n)))
AND length(nodes(path)) = 7
RETURN path,
reduce(distance = 0, edge in relationships(path) | distance + edge.distance)
AS totalDistance
ORDER BY totalDistance ASC
LIMIT 1
It does all permutations of available routes which are equal to the number of nodes (for this example it is 7), calculates lengths of all these paths and returns the shortest one.
neo4j may be a fine piece of software, but I wouldn't expect it to be of much help in solving this NP-hard problem. Instead, I would point you to an integer program solver (this one, perhaps, but I can't vouch for it) and suggest that you formulate this problem as an integer program as follows.
For each flight f, we create a 0-1 variable x(f) that is 1 if flight f is taken and 0 if flight f is not taken. The objective is to minimize the total cost of the flights (I'm going to assume that each purchase is an independent decision; if not, then you have some more work to do).
minimize sum_{flights f} cost(f) x(f)
Now we need some constraints. Each week, we purchase exactly one flight.
for all weeks i, sum_{flights f in week i} x(f) = 1
We can be in only one place at a time, so if we fly into city v for week i, then we fly out of city v for week i+1. We express this constraint with a strange but idiomatic linear equation.
for all weeks i, for all cities v,
sum_{flights f in week i to city v} x(f) -
sum_{flights f in week i+1 from city v} x(f) = 0
We can fly into each city at most once. We can fly out of each city at most once. This is how we enforce the constraint of visiting only once.
for all cities v,
sum_{flights f to city v} x(v) <= 1
for all cities v,
sum_{flights f from city v} x(v) <= 1
We're almost done. I'm going to assume at this point that the journey begins and ends in a home city u known ahead of time. For the first week, delete all flights not departing from u. For the last week, delete all flights not arriving at u. The flexibility of integer programming, however, means that it's easy to make other arrangements.

Resources