Open In App

Shortest path with one curved edge in an undirected Graph

Improve
Improve
Like Article
Like
Save
Share
Report

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. Your 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: 2
Explanation: 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 : 1
Explanation: Take the curved path from 1 to 2 which costs 1. 

Approach: To solve the problem follow the below idea:

  • The idea is to use Dijkstra’s algorithm to find the shortest path from source vertex a to all other vertices in the graph using the straight edges and store the result in array da[], and then from the destination vertex b to all other vertices and store the result in db[]. 
  • Now, iterate through all the curved edges in the graph and find the minimum distance between node a and node b that we can get by taking at most one curved edge. 
  • We can find this by calculating the distance from a to u and from v to b, where (u, v, cw) is the curved edge plus the weights of the curved edge. 
  • Now take the minimum of this value and the existing minimum distance from a to b that is stored in da[b]. Hence we are checking all the possibilities of taking exactly one curved edge, so we can guarantee that we are getting the shortest distance.
  • 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. 
  • Now, check if the resulting minimum distance is greater than or equal to 1000000001, that indicates that there is no path from a to b, and return -1.

Below are the steps for the above approach:

  • Make an adjacency list from the given edges.
  • Run Dijkstra considering node a, as the source node to find the shortest distance from node a to all other nodes in the graph and store the result in a vector say da where each element represents the shortest distance from node a to that node.
  • Run Dijkstra considering node b, as the source node to find the shortest distance from node b, to all other nodes in the graph and store the result in a vector say db where each element represents the shortest distance from node b to that node.
  • Initialize a variable say ans = da[b], means without using any curved edges.
  • Run a loop over the edges, and find minimum of da[u] + cw + db[v] and da[v] + cw + db[u].
  • If ans is greater than or equal to 1000000001, return -1. Else, return ans.

Below are the steps for the above approach:

C++




// C++ code for the above approach:
#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()
{
 
    int n = 4, m = 4;
    int a = 2, b = 4;
    vector<vector<int> > edges = { { 1, 2, 1, 4 },
                                   { 1, 3, 2, 4 },
                                   { 1, 4, 3, 1 },
                                   { 2, 4, 6, 5 } };
 
    // Function Call
    int ans = shortestPath(n, m, a, b, edges);
    cout << ans;
 
    return 0;
}


Java




import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.PriorityQueue;
 
public class DijkstraShortestPath {
    static int INF = 1000000001;
 
    public static int[] dijkstra(int u, int b, int n, List<List<Pair>> adj) {
        int[] dis = new int[n + 1];
        Arrays.fill(dis, INF);
        PriorityQueue<Pair> pq = new PriorityQueue<>();
        pq.add(new Pair(0, u));
        dis[u] = 0;
 
        while (!pq.isEmpty()) {
            Pair node = pq.poll();
            int d = node.first;
            int v = node.second;
 
            if (d > dis[v]) {
                continue;
            }
 
            for (Pair edge : adj.get(v)) {
                int to = edge.first;
                int weight = edge.second;
                if (dis[to] > dis[v] + weight) {
                    dis[to] = dis[v] + weight;
                    pq.add(new Pair(dis[to], to));
                }
            }
        }
 
        return dis;
    }
 
    public static int shortestPath(int n, int m, int a, int b, int[][] edges) {
        List<List<Pair>> adj = new ArrayList<>();
        List<Triple> curved = new ArrayList<>();
 
        for (int i = 0; i <= n; i++) {
            adj.add(new ArrayList<>());
        }
 
        for (int[] edge : edges) {
            int u = edge[0];
            int v = edge[1];
            int w = edge[2];
            int cw = edge[3];
            adj.get(u).add(new Pair(v, w));
            adj.get(v).add(new Pair(u, w));
            curved.add(new Triple(u, v, cw));
        }
 
        int[] da = dijkstra(a, b, n, adj);
        int[] db = dijkstra(b, a, n, adj);
        int ans = da[b];
 
        for (Triple triple : curved) {
            int u = triple.first;
            int v = triple.second;
            int cw = triple.third;
            ans = Math.min(ans, da[u] + cw + db[v]);
            ans = Math.min(ans, da[v] + cw + db[u]);
        }
 
        if (ans >= INF) {
            return -1;
        }
 
        return ans;
    }
 
    public static void main(String[] args) {
        int n = 4, m = 4;
        int a = 2, b = 4;
        int[][] edges = {
                {1, 2, 1, 4},
                {1, 3, 2, 4},
                {1, 4, 3, 1},
                {2, 4, 6, 5}
        };
        int ans = shortestPath(n, m, a, b, edges);
        System.out.println(ans);
    }
 
    static class Pair implements Comparable<Pair> {
        int first;
        int second;
 
        public Pair(int first, int second) {
            this.first = first;
            this.second = second;
        }
 
        @Override
        public int compareTo(Pair other) {
            return Integer.compare(first, other.first);
        }
    }
 
    static class Triple {
        int first;
        int second;
        int third;
 
        public Triple(int first, int second, int third) {
            this.first = first;
            this.second = second;
            this.third = third;
        }
    }
}


Python3




import heapq
 
 
def dijkstra(u, b, n, adj):
    dis = [1000000001] * (n+1)
    pq = [(0, u)]
    dis[u] = 0
 
    while pq:
        d, u = heapq.heappop(pq)
 
        if d > dis[u]:
            continue
 
        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 u, v, w, cw in edges:
        adj[u].append((v, w))
        adj[v].append((u, w))
        curved.append((u, v, cw))
 
    da = dijkstra(a, b, n, adj)
    db = dijkstra(b, a, n, adj)
    ans = da[b]
 
    for u, v, cw in curved:
        ans = min(ans, da[u] + cw + db[v])
        ans = min(ans, da[v] + cw + db[u])
 
    if ans >= 1000000001:
        return -1
    return ans
 
 
# Driver code
if __name__ == '__main__':
    n, m = 4, 4
    a, b = 2, 4
    edges = [
        [1, 2, 1, 4],
        [1, 3, 2, 4],
        [1, 4, 3, 1],
        [2, 4, 6, 5]
    ]
    ans = shortest_path(n, m, a, b, edges)
    print(ans)


C#




using System;
using System.Collections.Generic;
using System.Linq;
 
public class DijkstraShortestPath
{
    static int INF = 1000000001;
 
    public static int[] Dijkstra(int u, int b, int n, List<List<Pair>> adj)
    {
        int[] dis = new int[n + 1];
        for (int i = 0; i <= n; i++)
        {
            dis[i] = INF;
        }
 
        PriorityQueue<Pair> pq = new PriorityQueue<Pair>();
        pq.Enqueue(new Pair(0, u));
        dis[u] = 0;
 
        while (pq.Count > 0)
        {
            Pair node = pq.Dequeue();
            int d = node.First;
            int v = node.Second;
 
            if (d > dis[v])
            {
                continue;
            }
 
            foreach (Pair edge in adj[v])
            {
                int to = edge.First;
                int weight = edge.Second;
                if (dis[to] > dis[v] + weight)
                {
                    dis[to] = dis[v] + weight;
                    pq.Enqueue(new Pair(dis[to], to));
                }
            }
        }
 
        return dis;
    }
 
    public static int ShortestPath(int n, int m, int a, int b, int[][] edges)
    {
        List<List<Pair>> adj = new List<List<Pair>>();
        List<Triple> curved = new List<Triple>();
 
        for (int i = 0; i <= n; i++)
        {
            adj.Add(new List<Pair>());
        }
 
        foreach (int[] edge in edges)
        {
            int u = edge[0];
            int v = edge[1];
            int w = edge[2];
            int cw = edge[3];
            adj[u].Add(new Pair(v, w));
            adj[v].Add(new Pair(u, w));
            curved.Add(new Triple(u, v, cw));
        }
 
        int[] da = Dijkstra(a, b, n, adj);
        int[] db = Dijkstra(b, a, n, adj);
        int ans = da[b];
 
        foreach (Triple triple in curved)
        {
            int u = triple.First;
            int v = triple.Second;
            int cw = triple.Third;
            ans = Math.Min(ans, da[u] + cw + db[v]);
            ans = Math.Min(ans, da[v] + cw + db[u]);
        }
 
        if (ans >= INF)
        {
            return -1;
        }
 
        return ans;
    }
 
    public static void Main()
    {
        int n = 4, m = 4;
        int a = 2, b = 4;
        int[][] edges = {
            new int[] { 1, 2, 1, 4 },
            new int[] { 1, 3, 2, 4 },
            new int[] { 1, 4, 3, 1 },
            new int[] { 2, 4, 6, 5 }
        };
        int ans = ShortestPath(n, m, a, b, edges);
        Console.WriteLine(ans);
    }
}
 
public class Pair : IComparable<Pair>
{
    public int First { get; set; }
    public int Second { get; set; }
 
    public Pair(int first, int second)
    {
        First = first;
        Second = second;
    }
 
    public int CompareTo(Pair other)
    {
        return First.CompareTo(other.First);
    }
}
 
public class Triple
{
    public int First { get; set; }
    public int Second { get; set; }
    public int Third { get; set; }
 
    public Triple(int first, int second, int third)
    {
        First = first;
        Second = second;
        Third = third;
    }
}
 
public class PriorityQueue<T> where T : IComparable<T>
{
    private List<T> list = new List<T>();
 
    public int Count => list.Count;
 
    public void Enqueue(T value)
    {
        list.Add(value);
        int child = list.Count - 1;
        while (child > 0)
        {
            int parent = (child - 1) / 2;
            if (list[child].CompareTo(list[parent]) >= 0)
            {
                break;
            }
            T tmp = list[child];
            list[child] = list[parent];
            list[parent] = tmp;
            child = parent;
        }
    }
 
    public T Dequeue()
    {
        if (list.Count == 0)
        {
            throw new InvalidOperationException("Queue is empty.");
        }
        T frontItem = list[0];
        int lastIndex = list.Count - 1;
        T lastItem = list[lastIndex];
        list.RemoveAt(lastIndex);
        if (list.Count > 0)
        {
            list[0] = lastItem;
            int parent = 0;
            while (true)
            {
                int leftChild = parent * 2 + 1;
                if (leftChild >= list.Count)
                {
                    break;
                }
                int rightChild = leftChild + 1;
                int minChild = (rightChild < list.Count && list[rightChild].CompareTo(list[leftChild]) < 0) ? rightChild : leftChild;
                if (list[parent].CompareTo(list[minChild]) <= 0)
                {
                    break;
                }
                T tmp = list[parent];
                list[parent] = list[minChild];
                list[minChild] = tmp;
                parent = minChild;
            }
        }
        return frontItem;
    }
 
    public T Peek()
    {
        if (list.Count == 0)
        {
            throw new InvalidOperationException("Queue is empty.");
        }
        return list[0];
    }
 
    public bool Contains(T value)
    {
        return list.Contains(value);
    }
}


Javascript




function dijkstra(u, b, n, adj) {
    const dis = new Array(n + 1).fill(1000000001);
    const pq = new PriorityQueue(); // Implement a priority queue
    dis[u] = 0;
    pq.enqueue(0, u);
 
    while (!pq.isEmpty()) {
        const [du, u] = pq.dequeue();
 
        if (du > dis[u]) continue;
 
        for (const [v, w] of adj[u]) {
            if (dis[v] > dis[u] + w) {
                dis[v] = dis[u] + w;
                pq.enqueue(dis[v], v);
            }
        }
    }
    return dis;
}
 
class PriorityQueue {
    constructor() {
        this.elements = [];
    }
 
    enqueue(priority, element) {
        this.elements.push([priority, element]);
        this.elements.sort((a, b) => a[0] - b[0]);
    }
 
    dequeue() {
        return this.elements.shift();
    }
 
    isEmpty() {
        return this.elements.length === 0;
    }
}
 
function shortestPath(n, m, a, b, edges) {
    const adj = new Array(n + 1).fill(null).map(() => []);
    const curved = [];
 
    for (let i = 0; i < m; i++) {
        const [u, v, w, cw] = edges[i];
 
        adj[u].push([v, w]);
        adj[v].push([u, 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];
 
    for (let i = 0; i < m; i++) {
        const [u, v, cw] = curved[i];
 
        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
const n = 4, m = 4;
const a = 2, b = 4;
const edges = [[1, 2, 1, 4], [1, 3, 2, 4], [1, 4, 3, 1], [2, 4, 6, 5]];
 
// Function call
const ans = shortestPath(n, m, a, b, edges);
console.log(ans);


Output

2

Time Complexity: O((m+n)log(n)), As we the has n nodes and m edges
Auxiliary Space: O(n+m), For storing the adjacency list and distance vector

Related Articles:



Last Updated : 16 Oct, 2023
Like Article
Save Article
Previous
Next
Share your thoughts in the comments
Similar Reads