Open In App

Modify shortest distance between source and destination to K

Last Updated : 29 Feb, 2024
Improve
Improve
Like Article
Like
Save
Share
Report

Given an undirected weighted connected graph with N nodes and M edges. The weight of the edges given can be a positive integer or -1. Your task is to replace -1 weights with a positive weight in range [1, 2*109] such that the shortest distance between source node and destination node becomes equal to target distance. Return the array of modified and unmodified edges if the target distance is achievable otherwise return an empty array.

Examples:

Input: N = 5, edges = {{4,1,-1},{2,0,-1},{0,3,-1},{4,3,-1}}, source = 0, destination = 1, target = 5
Output: {{4,1,1},{2,0,1},{0,3,3},{4,3,1}}
Explanation: The below graph shows a possible modification of edges so that the shortest distance between node 0 to node 5 become equal to target distance 5.

Shortest1-(1)

Input: N = 3, edges = {{0,1,-1},{0,2,5}}, source = 0, destination = 2, target = 6
Output: {}
Explanation: There is a direct edge between 0 to 2 with weight 5 and it’s not possible to achieve the target distance 6.

Shortest2-(1)

Approach: Using Shortest Path Dijkstra Algorithm

  • First, identify the edge case scenarios where achieving the target distance is not possible.
    • Compute the shortest path from the given source to the destination, excluding edges with a weight of -1 from the adjacency list. Check if this computed distance is greater than the target. If it is, reaching the target is not possible.
    • If the computed distance is equal to the target, return the edges list by substituting all -1 weights with a large integer.
  • In cases where neither of the above conditions holds true, systematically introduce the edges with -1 weights into the adjacency list one by one. After each addition, determine the new shortest distance from the source to the destination. If this distance is less than or equal to the target, it signifies that achieving the target is possible. Calculate the required weight for the current edge, which is (target – shortest_distance). Update the weight of the current edge accordingly, and for the remaining edges with -1 weights, replace their weights with a large integer. Finally, return the modified edges vector as the solution to the problem.

Step-by-step algorithm:

  • Create Adjacency List:
    • Build an adjacency list represented as a vector of vector<pair<int,int>> from the given edges.
    • For an undirected edge [u,v,w], set Adj[u] to {{v,w}} and Adj[v] to {{u,w}}.
    • Exclude edges with a weight of -1 from the list.
  • Implement Dijkstra’s Algorithm:
    • Define a function to execute the standard Dijkstra Algorithm.
    • Set up an initial configuration using a priority queue (min-heap) to store minimum distances.
    • Create a distance vector of size n, initializing all elements to infinity.
    • Mark the source distance as 0.
    • Insert {0, source} into the priority queue.
    • Iterate over the priority queue until it is empty:
      • Extract the node and distance from the top of the priority queue.
      • Traverse neighbors of the current node, updating distances and inserting them into the priority queue.
  • Check edge case when it’s not possible to achieve the target:
    • To handle the case of negative weight edges, find the shortest distance from the source to the destination using the Dijkstra function.
    • If the computed shortest distance is less than the target, return an empty list as the target is not achievable.
    • If the computed shortest distance equals the target:
      • Replace all negative (-1) weights of the edges with a large integer and return the edges vector.
  • Replace Negative Weights with Minimum Positive Integer:
    • Iterate over the list of edges.
    • If an edge with weight -1 is encountered:
    • Insert this edge into the adjacency list and find the shortest distance by replacing the edge weight with the minimum positive integer 1.
    • If the new shortest distance is less than or equal to the target:
      • Append (target – shortest_distance) to this edge, and mark all other edges with a large integer.
      • Finally, return the edges vector.

Below is the implementation of the above approach:

C++14




#include<bits/stdc++.h>
using namespace std;
 
class Solution {
public:
    // Dijkstra Algorithm
    int dijkstra(vector<vector<pair<int, int>>>& adj, int src, int dest, int n){
        priority_queue<pair<int, int>, vector<pair<int, int>>, greater<pair<int, int>>> pq;
        vector<int> dist(n, INT_MAX);
        dist[src] = 0;
        pq.push({0, src});
         
        while(!pq.empty()){
            int d = pq.top().first;
            int node = pq.top().second;
            pq.pop();
             
            for(auto neighbor : adj[node]){
                int adjNode = neighbor.first;
                int adjWeight = neighbor.second;
                 
                if(dist[adjNode] > d + adjWeight){
                    dist[adjNode] = d + adjWeight;
                    pq.push({dist[adjNode], adjNode});
                }
            }
        }
        return dist[dest];
    }
 
    vector<vector<int>> modifyEdges(int n, vector<vector<int>>& edges, int src, int dest, int target) {
        vector<vector<pair<int, int>>> adj(n);
         
        /*
           Step 1: Create an adjacency list from the given edges for undirected edges [u, v, w].
           The adjacency list is represented as Adj[u] = {{v, w}} and Adj[v] = {{u, w}}.
           Exclude edges with a weight of -1 from the list.
        */
 
        for (auto edge : edges){
            int weight = edge[2];
            if (weight != -1) {
                int u = edge[0];
                int v = edge[1];
                adj[u].push_back({v, weight});
                adj[v].push_back({u, weight});
            }
        }
         
        /*
           Step 2: Check the base case.
           Find the shortest distance from the source to the destination using Dijkstra's algorithm, ignoring edges with a weight of -1.
           This is done to verify if the shortest distance from source to destination, without considering -1 weighted edges, is greater than the target.
           If so, it implies that reaching the destination with the target distance is not possible if we include edges with a weight of -1.
           In such cases, return an empty list.
        */
 
        int shortestPath = dijkstra(adj, src, dest, n);
         
        /*
           Step 3: Base case condition check.
           If it is not possible to achieve the target distance, return an empty list.
        */
 
        if (shortestPath < target){
            return {};
        }
         
        /*
           Step 4: Check if the target distance is already achieved.
           If the shortest distance is equal to the target distance, proceed to modify edges.
        */
 
        if (shortestPath == target){
            for (int i = 0; i < edges.size(); i++){
                int weight = edges[i][2];
                if (weight == -1){
                    edges[i][2] = INT_MAX;
                }
            }
            return edges;
        }
         
        /*
           Step 5: Try adding edges with weight -1 one by one into the graph.
           Find the shortest distance after adding each modified edge.
           If, at any point, the shortest distance becomes less than or equal to the target distance, adjust the weights accordingly.
           Replace the remaining -1 weighted edges with a large integer, as they will not be part of the shortest path.
           This ensures that the target distance is achieved, and the modified edges are returned as the answer.
        */
 
        for (int i = 0; i < edges.size(); i++){
            int weight = edges[i][2];
            if (weight == -1){
                edges[i][2] = 1;
                int u = edges[i][0];
                int v = edges[i][1];
                adj[u].push_back({v, 1});
                adj[v].push_back({u, 1});
                 
                int newShortestPath = dijkstra(adj, src, dest, n);
 
                if (newShortestPath <= target){
                    edges[i][2] += (target - newShortestPath);
                    for (int j = 0; j < edges.size(); j++){
                        int weight = edges[j][2];
                        if (weight == -1){
                            edges[j][2] = INT_MAX;
                        }
                    }
                    return edges;
                }
            }
        }
        return {};
    }
};
 
int main() {
    Solution obj;
 
    int n = 4;
    vector<vector<int>> edges = {{1,0,4},{1,2,3},{2,3,5},{0,3,-1}};
    int src = 0;
    int dest = 2;
    int target = 6;
 
    vector<vector<int>> result = obj.modifyEdges(n, edges, src, dest, target);
 
    if (result.empty()) {
        cout << "No valid modification found to achieve the target distance." << endl;
    } else {
        cout << "Modified Edges: " << endl;
        for (const auto &edge : result) {
            cout << edge[0] << " -> " << edge[1] << " : " << edge[2] << endl;
        }
    }
    return 0;
}


Java




import java.util.*;
 
class Solution {
 
    // Dijkstra Algorithm
    private int dijkstra(List<List<int[]>> adj, int src, int dest, int n) {
        PriorityQueue<int[]> pq = new PriorityQueue<>(Comparator.comparingInt(a -> a[0]));
        int[] dist = new int[n];
        Arrays.fill(dist, Integer.MAX_VALUE);
        dist[src] = 0;
        pq.add(new int[]{0, src});
 
        while (!pq.isEmpty()) {
            int[] top = pq.poll();
            int d = top[0];
            int node = top[1];
 
            for (int[] neighbor : adj.get(node)) {
                int adjNode = neighbor[0];
                int adjWeight = neighbor[1];
 
                if (dist[adjNode] > d + adjWeight) {
                    dist[adjNode] = d + adjWeight;
                    pq.add(new int[]{dist[adjNode], adjNode});
                }
            }
        }
        return dist[dest];
    }
 
    public List<List<Integer>> modifyEdges(int n,
                                           List<List<Integer>> edges,
                                           int src, int dest,
                                           int target) {
        List<List<int[]>> adj = new ArrayList<>(n);
 
        // Step 1: Create an adjacency list from the given edges
        for (int i = 0; i < n; i++) {
            adj.add(new ArrayList<>());
        }
 
        for (List<Integer> edge : edges) {
            int weight = edge.get(2);
            if (weight != -1) {
                int u = edge.get(0);
                int v = edge.get(1);
                adj.get(u).add(new int[]{v, weight});
                adj.get(v).add(new int[]{u, weight});
            }
        }
 
        // Step 2: Check the base case
        int shortestPath = dijkstra(adj, src, dest, n);
 
        if (shortestPath < target) {
            return new ArrayList<>();
        }
 
        // Step 3: Base case condition check
        if (shortestPath == target) {
            for (List<Integer> edge : edges) {
                int weight = edge.get(2);
                if (weight == -1) {
                    edge.set(2, Integer.MAX_VALUE);
                }
            }
            return edges;
        }
 
        // Step 4: Try adding edges with weight -1 one by one into the graph
        for (List<Integer> edge : edges) {
            int weight = edge.get(2);
            if (weight == -1) {
                edge.set(2, 1);
                int u = edge.get(0);
                int v = edge.get(1);
                adj.get(u).add(new int[]{v, 1});
                adj.get(v).add(new int[]{u, 1});
 
                int newShortestPath = dijkstra(adj, src, dest, n);
 
                if (newShortestPath <= target) {
                    edge.set(2, edge.get(2) + (target - newShortestPath));
                    for (List<Integer> e : edges) {
                        int w = e.get(2);
                        if (w == -1) {
                            e.set(2, Integer.MAX_VALUE);
                        }
                    }
                    return edges;
                }
            }
        }
        return new ArrayList<>();
    }
}
 
public class Main {
    public static void main(String[] args) {
        Solution obj = new Solution();
 
        int n = 4;
        List<List<Integer>> edges = Arrays.asList(
                Arrays.asList(1, 0, 4),
                Arrays.asList(1, 2, 3),
                Arrays.asList(2, 3, 5),
                Arrays.asList(0, 3, -1)
        );
        int src = 0;
        int dest = 2;
        int target = 6;
 
        List<List<Integer>> result = obj.modifyEdges(n, edges, src, dest, target);
 
        if (result.isEmpty()) {
            System.out.println("No valid modification found to achieve the target distance.");
        } else {
            System.out.println("Modified Edges:");
            for (List<Integer> edge : result) {
                System.out.println(edge.get(0) + " -> " + edge.get(1) + " : " + edge.get(2));
            }
        }
    }
}
 
// This code is contributed by akshitaguprzj3


Python3




import heapq
 
class Solution:
    def dijkstra(self, adj, src, dest, n):
        pq = [(0, src)]
        dist = [float('inf')] * n
        dist[src] = 0
 
        while pq:
            d, node = heapq.heappop(pq)
 
            for neighbor in adj[node]:
                adjNode, adjWeight = neighbor
 
                if dist[adjNode] > d + adjWeight:
                    dist[adjNode] = d + adjWeight
                    heapq.heappush(pq, (dist[adjNode], adjNode))
 
        return dist[dest]
 
    def modifyEdges(self, n, edges, src, dest, target):
        adj = [[] for _ in range(n)]
 
        # Step 1: Create an adjacency list
        for edge in edges:
            weight = edge[2]
            if weight != -1:
                u, v = edge[0], edge[1]
                adj[u].append((v, weight))
                adj[v].append((u, weight))
 
        # Step 2: Check base case
        shortestPath = self.dijkstra(adj, src, dest, n)
 
        # Step 3: Base case condition check
        if shortestPath < target:
            return []
 
        # Step 4: Check if target distance is already achieved
        if shortestPath == target:
            for i in range(len(edges)):
                weight = edges[i][2]
                if weight == -1:
                    edges[i][2] = float('inf')
            return edges
 
        # Step 5: Try adding edges with weight -1 one by one
        for i in range(len(edges)):
            weight = edges[i][2]
            if weight == -1:
                edges[i][2] = 1
                u, v = edges[i][0], edges[i][1]
                adj[u].append((v, 1))
                adj[v].append((u, 1))
 
                newShortestPath = self.dijkstra(adj, src, dest, n)
 
                if newShortestPath <= target:
                    edges[i][2] += (target - newShortestPath)
                    for j in range(len(edges)):
                        weight = edges[j][2]
                        if weight == -1:
                            edges[j][2] = float('inf')
                    return edges
 
        return []
 
 
if __name__ == "__main__":
    obj = Solution()
 
    n = 4
    edges = [[1, 0, 4], [1, 2, 3], [2, 3, 5], [0, 3, -1]]
    src = 0
    dest = 2
    target = 6
 
    result = obj.modifyEdges(n, edges, src, dest, target)
 
    if not result:
        print("No valid modification found to achieve the target distance.")
    else:
        print("Modified Edges:")
        for edge in result:
            print(f"{edge[0]} -> {edge[1]} : {edge[2]}")


C#




using System;
using System.Collections.Generic;
using System.Linq;
 
public class Solution
{
    // Dijkstra Algorithm
    public int Dijkstra(List<List<Tuple<int, int>>> adj, int src, int dest, int n)
    {
        // Priority queue to store nodes with their distances
        PriorityQueue<Tuple<int, int>> pq = new PriorityQueue<Tuple<int, int>>((x, y) => x.Item1.CompareTo(y.Item1)); // Provide comparison function
        // Array to store distances from source node
        int[] dist = new int[n];
        Array.Fill(dist, int.MaxValue);
        dist[src] = 0;
        pq.Enqueue(new Tuple<int, int>(0, src));
 
        while (pq.Count > 0)
        {
            Tuple<int, int> tuple = pq.Dequeue();
            int d = tuple.Item1;
            int node = tuple.Item2;
 
            foreach (Tuple<int, int> neighbor in adj[node])
            {
                int adjNode = neighbor.Item1;
                int adjWeight = neighbor.Item2;
 
                if (dist[adjNode] > d + adjWeight)
                {
                    dist[adjNode] = d + adjWeight;
                    pq.Enqueue(new Tuple<int, int>(dist[adjNode], adjNode));
                }
            }
        }
        return dist[dest];
    }
 
    public List<List<int>> ModifyEdges(int n, List<List<int>> edges, int src, int dest, int target)
    {
        List<List<Tuple<int, int>>> adj = new List<List<Tuple<int, int>>>();
 
        // Create an adjacency list from the given edges
        foreach (var _ in Enumerable.Range(0, n))
        {
            adj.Add(new List<Tuple<int, int>>());
        }
 
        foreach (var edge in edges)
        {
            int weight = edge[2];
            if (weight != -1)
            {
                int u = edge[0];
                int v = edge[1];
                adj[u].Add(new Tuple<int, int>(v, weight));
                adj[v].Add(new Tuple<int, int>(u, weight));
            }
        }
 
        // Check the base case
        int shortestPath = Dijkstra(adj, src, dest, n);
 
        if (shortestPath < target)
        {
            return new List<List<int>>();
        }
 
        //  Handle the case where the target distance is already achieved
        if (shortestPath == target)
        {
            foreach (var edge in edges)
            {
                int weight = edge[2];
                if (weight == -1)
                {
                    edge[2] = int.MaxValue;
                }
            }
            return edges;
        }
 
        // Try adding edges with weight -1 and adjust weights accordingly
        foreach (var edge in edges)
        {
            int weight = edge[2];
            if (weight == -1)
            {
                edge[2] = 1;
                int u = edge[0];
                int v = edge[1];
                adj[u].Add(new Tuple<int, int>(v, 1));
                adj[v].Add(new Tuple<int, int>(u, 1));
 
                int newShortestPath = Dijkstra(adj, src, dest, n);
 
                if (newShortestPath <= target)
                {
                    edge[2] += (target - newShortestPath);
                    foreach (var edge2 in edges)
                    {
                        int weight2 = edge2[2];
                        if (weight2 == -1)
                        {
                            edge2[2] = int.MaxValue;
                        }
                    }
                    return edges;
                }
            }
        }
        return new List<List<int>>();
    }
 
    static void Main(string[] args)
    {
        Solution obj = new Solution();
 
        int n = 4;
        List<List<int>> edges = new List<List<int>> { new List<int> { 1, 0, 4 }, new List<int> { 1, 2, 3 }, new List<int> { 2, 3, 5 }, new List<int> { 0, 3, -1 } };
        int src = 0;
        int dest = 2;
        int target = 6;
 
        List<List<int>> result = obj.ModifyEdges(n, edges, src, dest, target);
 
        if (result.Count == 0)
        {
            Console.WriteLine("No valid modification found to achieve the target distance.");
        }
        else
        {
            Console.WriteLine("Modified Edges:");
            foreach (var edge in result)
            {
                Console.WriteLine($"{edge[0]} -> {edge[1]} : {edge[2]}");
            }
        }
    }
}
 
// Priority queue implementation
public class PriorityQueue<T>
{
    private readonly List<T> _heap;
    private readonly Comparison<T> _compare;
 
    public PriorityQueue(Comparison<T> compare)
    {
        _heap = new List<T>();
        _compare = compare;
    }
 
    public int Count => _heap.Count;
 
    public void Enqueue(T item)
    {
        _heap.Add(item);
        int i = _heap.Count - 1;
        while (i > 0)
        {
            int parent = (i - 1) / 2;
            if (_compare(_heap[i], _heap[parent]) >= 0) break;
            Swap(i, parent);
            i = parent;
        }
    }
 
    public T Dequeue()
    {
        int n = _heap.Count - 1;
        T result = _heap[0];
        _heap[0] = _heap[n];
        _heap.RemoveAt(n);
        n--;
        int i = 0;
        while (true)
        {
            int left = 2 * i + 1;
            int right = 2 * i + 2;
            if (left > n) break;
            int next = left;
            if (right <= n && _compare(_heap[left], _heap[right]) > 0)
                next = right;
            if (_compare(_heap[next], _heap[i]) >= 0) break;
            Swap(i, next);
            i = next;
        }
        return result;
    }
 
    private void Swap(int i, int j)
    {
        T temp = _heap[i];
        _heap[i] = _heap[j];
        _heap[j] = temp;
    }
}


Javascript




class Solution {
    //Dijkstra Algorithm
    dijkstra(adj, src, dest, n) {
        const pq = [[0, src]];
        const dist = Array(n).fill(Infinity);
        dist[src] = 0;
 
        while (pq.length > 0) {
            const [d, node] = pq.shift();
 
            for (const [adjNode, adjWeight] of adj[node]) {
                if (dist[adjNode] > d + adjWeight) {
                    dist[adjNode] = d + adjWeight;
                    pq.push([dist[adjNode], adjNode]);
                    pq.sort((a, b) => a[0] - b[0]);
                }
            }
        }
 
        return dist[dest];
    }
 
    modifyEdges(n, edges, src, dest, target) {
        const adj = Array(n).fill().map(() => []);
 
        // Step 1: Create an adjacency list
        for (const edge of edges) {
            const weight = edge[2];
            if (weight !== -1) {
                const [u, v] = [edge[0], edge[1]];
                adj[u].push([v, weight]);
                adj[v].push([u, weight]);
            }
        }
 
        // Step 2: Check base case
        const shortestPath = this.dijkstra(adj, src, dest, n);
 
        // Step 3: Base case condition check
        if (shortestPath < target) {
            return [];
        }
 
        // Step 4: Check if target distance is already achieved
        if (shortestPath === target) {
            for (let i = 0; i < edges.length; i++) {
                const weight = edges[i][2];
                if (weight === -1) {
                    edges[i][2] = Infinity;
                }
            }
            return edges;
        }
 
        // Step 5: Try adding edges with weight -1 one by one
        for (let i = 0; i < edges.length; i++) {
            const weight = edges[i][2];
            if (weight === -1) {
                edges[i][2] = 1;
                const [u, v] = [edges[i][0], edges[i][1]];
                adj[u].push([v, 1]);
                adj[v].push([u, 1]);
 
                const newShortestPath = this.dijkstra(adj, src, dest, n);
 
                if (newShortestPath <= target) {
                    edges[i][2] += (target - newShortestPath);
                    for (let j = 0; j < edges.length; j++) {
                        const weight = edges[j][2];
                        if (weight === -1) {
                            edges[j][2] = Infinity;
                        }
                    }
                    return edges;
                }
            }
        }
 
        return [];
    }
}
 
// Main
const obj = new Solution();
 
const n = 4;
const edges = [[1, 0, 4], [1, 2, 3], [2, 3, 5], [0, 3, -1]];
const src = 0;
const dest = 2;
const target = 6;
 
const result = obj.modifyEdges(n, edges, src, dest, target);
 
if (result.length === 0) {
    console.log("No valid modification found to achieve the target distance.");
} else {
    console.log("Modified Edges:");
    for (const edge of result) {
        console.log(`${edge[0]} -> ${edge[1]} : ${edge[2]}`);
    }
}


Output

Modified Edges: 
1 -> 0 : 4
1 -> 2 : 3
2 -> 3 : 5
0 -> 3 : 1







Time Complexity: O((V + E) * log(V)), where V is the number of vertices, and E is the number of edges.
Auxiliary Space: O(V + E)



Like Article
Suggest improvement
Share your thoughts in the comments

Similar Reads