Open In App

Shortest Path Using Atmost One Curved Edge

Last Updated : 31 Dec, 2023
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, 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: 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:

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++




// 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;
}


Java




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);
        }
    }
}


Python3




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)


C#




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




// 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


Output

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.



Like Article
Suggest improvement
Share your thoughts in the comments

Similar Reads