Given an undirected connected graph of n vertices and a list of m edges in a graph and for each pair of vertices that are connected by an edge. There are two edges between them, one curved edge and one straight edge i.e. the tuple (x, y, w1, w2) means that between vertices x and y, there is a straight edge with weight w1 and a curved edge with weight w2. You are given two vertices a and b and you have to go from a to b through a series of edges such that in the entire path you can use at most 1 curved edge, the task is to find the shortest path from a to b satisfying the above condition. If there is no path from a to b, return -1.
Examples:
Input: n = 4, m = 4, a = 2, b = 4, edges = {{1, 2, 1, 4}, {1, 3, 2, 4}, {1, 4, 3, 1}, {2, 4, 6, 5}}
Output: 2Explanation: We can follow the path 2 -> 1 -> 4. This gives a distance of 1+3 = 4 if we follow all straight paths. But we can take the curved path from 1 -> 4, which costs 1. This will result in a cost of 1+1 = 2
Input: n = 2, m = 1, a = 1, b = 2, edges = {{1, 2, 4, 1}}
Output: 1Explanation: Take the curved path from 1 to 2 which costs 1.
Approach: To solve the problem follow the below idea:
Idea is to find the shortest distance of all nodes from node a, without using any curved node. Then find the shortest distance of all nodes from node b, without using any curved node. Now for each node, we have to find minimum of da[u] + cw + db[v] and da[v] + cw + db[u]. cw is the weight of curved edge u-v, da[u] = minimum distance of node a to u without curved edge. db[u] = minimum distance of node b to u without curved edge.
Step-by-step approach:
- Make an adjacency list from the given edges.
- Run Dijkstra considering node a, as the source node.
- Run Dijkstra considering node b, as the source node.
- Initialize ans = da[b], means without using any curved edges.
- Run a loop over the egdes, and find minimum of da[u] + cw + db[v] and da[v] + cw + db[u].
- return the answer.
Below is the implementation of the above approach:
// C++ code for the above appraoch: #include <bits/stdc++.h> using namespace std;
vector< int > dijkstra( int u, int b, int n,
vector<pair< int , int > > adj[])
{ vector< int > dis;
dis.assign(n + 1, 1000000001);
priority_queue<pair< int , int >, vector<pair< int , int > >,
greater<pair< int , int > > >
pq;
dis[u] = 0;
pq.push({ 0, u });
while (!pq.empty()) {
int u = pq.top().second;
pq.pop();
for ( auto p : adj[u]) {
int v = p.first;
int w = p.second;
if (dis[v] > dis[u] + w) {
dis[v] = dis[u] + w;
pq.push({ dis[v], v });
}
}
}
return dis;
} int shortestPath( int n, int m, int a, int b,
vector<vector< int > >& edges)
{ vector<pair< int , int > > adj[n + 1];
vector<vector< int > > curved;
for ( int i = 0; i < m; i++) {
int u = edges[i][0];
int v = edges[i][1];
int w = edges[i][2];
int cw = edges[i][3];
adj[u].push_back({ v, w });
adj[v].push_back({ u, w });
// curved edge weight
curved.push_back({ u, v, cw });
}
vector< int > da = dijkstra(a, b, n, adj);
vector< int > db = dijkstra(b, a, n, adj);
int ans = da[b];
// ans = min distance from a -> b with at max one
// curved edge current ans without curved edge from
// a -> b = da[b]
for ( int i = 0; i < m; i++) {
int u = curved[i][0];
int v = curved[i][1];
int cw = curved[i][2];
ans = min(ans, da[u] + cw + db[v]);
ans = min(ans, da[v] + cw + db[u]);
}
if (ans >= 1000000001)
return -1;
return ans;
} // Drivers code int main()
{ // Number of nodes
int n = 54;
// Number of edges
int m = 4;
// Source node
int a = 2;
// Destination node
int b = 4;
// Edges in the format {u, v, weight,
// curved_edge_weight}
vector<vector< int > > edges = { { 1, 2, 1, 4 },
{ 1, 3, 2, 4 },
{ 1, 4, 3, 1 },
{ 2, 4, 6, 5 } };
int result = shortestPath(n, m, a, b, edges);
cout << "Minimum distance from node " << a
<< " to node " << b << " is: " ;
if (result == -1) {
cout << "No path exists." ;
}
else {
cout << result;
}
return 0;
} |
import java.util.*;
class ShortestPathWithCurvedEdge {
// Function to perform Dijkstra's algorithm to find the
// shortest paths from a source node to all other nodes
static List<Integer> dijkstra( int u, int b, int n,
List< int []>[] adj)
{
List<Integer> dis = new ArrayList<>(
Collections.nCopies(n + 1 , 1000000001 ));
PriorityQueue< int []> pq = new PriorityQueue<>(
Comparator.comparingInt(a -> a[ 0 ]));
dis.set(u, 0 );
pq.add( new int [] { 0 , u });
while (!pq.isEmpty()) {
int [] current = pq.poll();
int currentDistance = current[ 0 ];
int currentNode = current[ 1 ];
for ( int [] p : adj[currentNode]) {
int v = p[ 0 ];
int w = p[ 1 ];
if (dis.get(v) > dis.get(currentNode) + w) {
dis.set(v, dis.get(currentNode) + w);
pq.add( new int [] { dis.get(v), v });
}
}
}
return dis;
}
// Function to find the shortest path from node a to b
// with the possibility of using a curved edge
static int shortestPath( int n, int m, int a, int b,
List< int []> edges)
{
List< int []>[] adj = new ArrayList[n + 1 ];
for ( int i = 1 ; i <= n; i++) {
adj[i] = new ArrayList<>();
}
List< int []> curved = new ArrayList<>();
// Build adjacency list and list of curved edges
// from the given edges
for ( int [] edge : edges) {
int u = edge[ 0 ];
int v = edge[ 1 ];
int w = edge[ 2 ];
int cw = edge[ 3 ];
adj[u].add( new int [] { v, w });
adj[v].add( new int [] { u, w });
curved.add( new int [] { u, v, cw });
}
// Find shortest paths from a to b and b to a
List<Integer> da = dijkstra(a, b, n, adj);
List<Integer> db = dijkstra(b, a, n, adj);
int ans = da.get(b);
// Update the answer with the possibility of using
// curved edges
for ( int [] cur : curved) {
int u = cur[ 0 ];
int v = cur[ 1 ];
int cw = cur[ 2 ];
ans = Math.min(ans, da.get(u) + cw + db.get(v));
ans = Math.min(ans, da.get(v) + cw + db.get(u));
}
// If the answer is still greater than or equal to
// 1000000001, there is no valid path
if (ans >= 1000000001 )
return - 1 ;
return ans;
}
// Main function
public static void main(String[] args)
{
// Number of nodes
int n = 54 ;
// Number of edges
int m = 4 ;
// Source node
int a = 2 ;
// Destination node
int b = 4 ;
// Edges in the format {u, v, weight,
// curved_edge_weight}
List< int []> edges
= Arrays.asList( new int [] { 1 , 2 , 1 , 4 },
new int [] { 1 , 3 , 2 , 4 },
new int [] { 1 , 4 , 3 , 1 },
new int [] { 2 , 4 , 6 , 5 });
// Calculate the result and display it
int result = shortestPath(n, m, a, b, edges);
System.out.print( "Minimum distance from node " + a
+ " to node " + b + " is: " );
if (result == - 1 ) {
System.out.println( "No path exists." );
}
else {
System.out.println(result);
}
}
} |
import heapq
def dijkstra(u, b, n, adj):
dis = [ float ( 'inf' )] * (n + 1 )
dis[u] = 0
pq = [( 0 , u)]
while pq:
dist, u = heapq.heappop(pq)
for v, w in adj[u]:
if dis[v] > dis[u] + w:
dis[v] = dis[u] + w
heapq.heappush(pq, (dis[v], v))
return dis
def shortest_path(n, m, a, b, edges):
adj = [[] for _ in range (n + 1 )]
curved = []
for i in range (m):
u, v, w, cw = edges[i]
adj[u].append((v, w))
adj[v].append((u, w))
# curved edge weight
curved.append((u, v, cw))
da = dijkstra(a, b, n, adj)
db = dijkstra(b, a, n, adj)
ans = da[b]
# ans = min distance from a -> b with at max one
# curved edge. Current ans without curved edge from
# a -> b = da[b]
for i in range (m):
u, v, cw = curved[i]
ans = min (ans, da[u] + cw + db[v])
ans = min (ans, da[v] + cw + db[u])
if ans > = float ( 'inf' ):
return - 1
return ans
# Drivers code if __name__ = = "__main__" :
# Number of nodes
n = 54
# Number of edges
m = 4
# Source node
a = 2
# Destination node
b = 4
# Edges in the format [u, v, weight, curved_edge_weight]
edges = [
[ 1 , 2 , 1 , 4 ],
[ 1 , 3 , 2 , 4 ],
[ 1 , 4 , 3 , 1 ],
[ 2 , 4 , 6 , 5 ]
]
result = shortest_path(n, m, a, b, edges)
print (f "Minimum distance from node {a} to node {b} is: " , end = "")
if result = = - 1 :
print ( "No path exists." )
else :
print (result)
|
using System;
using System.Collections.Generic;
class Program
{ class PriorityQueue<T>
{
private SortedSet<T> set ;
public PriorityQueue(IComparer<T> comparer)
{
set = new SortedSet<T>(comparer);
}
public int Count => set .Count;
public void Enqueue(T item)
{
set .Add(item);
}
public T Dequeue()
{
T item = set .Min;
set .Remove(item);
return item;
}
}
static List< int > Dijkstra( int u, int b, int n, List<Tuple< int , int >>[] adj)
{
List< int > dis = new List< int >();
dis.AddRange( new int [n + 1]);
for ( int i = 0; i <= n; i++)
{
dis[i] = 1000000001;
}
var pq = new PriorityQueue<Tuple< int , int >>(Comparer<Tuple< int , int >>.Create((x, y) => x.Item1.CompareTo(y.Item1)));
dis[u] = 0;
pq.Enqueue( new Tuple< int , int >(0, u));
while (pq.Count > 0)
{
Tuple< int , int > top = pq.Dequeue();
int uu = top.Item2;
foreach ( var p in adj[uu])
{
int v = p.Item1;
int w = p.Item2;
if (dis[v] > dis[uu] + w)
{
dis[v] = dis[uu] + w;
pq.Enqueue( new Tuple< int , int >(dis[v], v));
}
}
}
return dis;
}
static int ShortestPath( int n, int m, int a, int b, List<List< int >> edges)
{
List<Tuple< int , int >>[] adj = new List<Tuple< int , int >>[n + 1];
for ( int i = 0; i <= n; i++)
{
adj[i] = new List<Tuple< int , int >>();
}
List<List< int >> curved = new List<List< int >>();
for ( int i = 0; i < m; i++)
{
int u = edges[i][0];
int v = edges[i][1];
int w = edges[i][2];
int cw = edges[i][3];
adj[u].Add( new Tuple< int , int >(v, w));
adj[v].Add( new Tuple< int , int >(u, w));
// curved edge weight
curved.Add( new List< int > { u, v, cw });
}
List< int > da = Dijkstra(a, b, n, adj);
List< int > db = Dijkstra(b, a, n, adj);
int ans = da[b];
// ans = min distance from a -> b with at max one
// curved edge current ans without curved edge from
// a -> b = da[b]
for ( int i = 0; i < m; i++)
{
int u = curved[i][0];
int v = curved[i][1];
int cw = curved[i][2];
ans = Math.Min(ans, da[u] + cw + db[v]);
ans = Math.Min(ans, da[v] + cw + db[u]);
}
if (ans >= 1000000001)
return -1;
return ans;
}
// Driver code
static void Main()
{
// Number of nodes
int n = 54;
// Number of edges
int m = 4;
// Source node
int a = 2;
// Destination node
int b = 4;
// Edges in the format {u, v, weight,
// curved_edge_weight}
List<List< int >> edges = new List<List< int >> {
new List< int > { 1, 2, 1, 4 },
new List< int > { 1, 3, 2, 4 },
new List< int > { 1, 4, 3, 1 },
new List< int > { 2, 4, 6, 5 }
};
int result = ShortestPath(n, m, a, b, edges);
Console.Write( "Minimum distance from node " + a +
" to node " + b + " is: " );
if (result == -1)
{
Console.Write( "No path exists." );
}
else
{
Console.Write(result);
}
}
} |
// Javascript code for the above approach // A simple priorityQueue implementation class PriorityQueue { // creates a PriorityQueue queue
// internally uses arrays to store the data
constructor(compare) {
this .queue = [];
this .compare = compare;
}
// adding to queue
enqueue(item) {
this .queue.push(item);
// sort to maintain PriorityQueue order
this .queue.sort( this .compare);
}
// dequeue operation using shift function
dequeue() {
if ( this .isEmpty()) {
return null ;
}
return this .queue.shift();
}
// isEmpty utility funtion
// to check whether the queue is empty
isEmpty() {
return this .queue.length === 0;
}
} function dijkstra(u, b, n, adj) {
const dis = Array(n + 1).fill(1000000001);
const pq = new PriorityQueue((a, b) => b.priority - a.priority);
dis[u] = 0;
pq.enqueue({
priority: 0, element: u
});
while (!pq.isEmpty()) {
const currentU = pq.dequeue().element;
for (const {
first: v, second: w
} of adj[currentU]) {
if (dis[v] > dis[currentU] + w) {
dis[v] = dis[currentU] + w;
pq.enqueue({
priority: dis[v], element: v
});
}
}
}
return dis;
} function shortestPath(n, m, a, b, edges) {
const adj = Array.from({
length: n + 1
}, () => []);
const curved = [];
for (let i = 0; i < m; i++) {
const u = edges[i][0];
const v = edges[i][1];
const w = edges[i][2];
const cw = edges[i][3];
adj[u].push({
first: v, second: w
});
adj[v].push({
first: u, second: w
});
// curved edge weight
curved.push([u, v, cw]);
}
const da = dijkstra(a, b, n, adj);
const db = dijkstra(b, a, n, adj);
let ans = da[b];
// ans = min distance from a -> b with at max one
// curved edge current ans without curved edge from
// a -> b = da[b]
for (let i = 0; i < m; i++) {
const u = curved[i][0];
const v = curved[i][1];
const cw = curved[i][2];
ans = Math.min(ans, da[u] + cw + db[v]);
ans = Math.min(ans, da[v] + cw + db[u]);
}
if (ans >= 1000000001) {
return -1;
}
return ans;
} // Driver code function main() {
// Number of nodes
const n = 54;
// Number of edges
const m = 4;
// Source node
const a = 2;
// Destination node
const b = 4;
// Edges in the format {u, v, weight, curved_edge_weight}
const edges = [
[1, 2, 1, 4],
[1, 3, 2, 4],
[1, 4, 3, 1],
[2, 4, 6, 5]
];
const result = shortestPath(n, m, a, b, edges);
console.log(`Minimum distance from node ${a} to node ${b} is: ${result === -1 ? 'No path exists.' : result}`);
} // Driver call main(); // This code is contributed by ragul21 |
Minimum distance from node 2 to node 4 is: 2
Time Complexity: As we the has n nodes and m edges, so the time complexity is O((m+n)log(n))
Auxiliary Space: Storing the adjacency list and distance vector takes O(n+m) space.