Open In App

Maximum Edges In The Path

Last Updated : 09 Dec, 2023
Improve
Improve
Like Article
Like
Save
Share
Report

Given a directed graph with n nodes and m edges. Each edge is assigned a weight. The graph can also be disconnected and there might be multiple edges and self-loops. The task is to choose a path such that the weights of the edges are in strictly increasing order and the path has the maximum possible number of edges(The path can contain the same vertices multiple times). Note:- The edges must be in the order of input

Example:

Input: n = 3, m = 3, inputEdges = {{3, 1, 3}, {1, 2, 1}, {2, 3, 2}}
Output: 2

Input: n = 5, m = 5, inputEdges = {{1, 3, 2}, {3, 2, 3}, {3, 4, 5}, {5, 4, 0}, {4, 5, 8}}
Output: 3

Approach:

The idea is to use a dynamic programming approach by maintaining a vector of maps (edges) where each map corresponds to a node and stores the maximum length of the path ending at that node with a particular weight.

For each input edge, calculates the length of the path ending at the starting node (a) with the given weight (w). It then checks if extending the path to the ending node (b) by including the current edge maintains the strictly increasing order of weights. If so, updates the information in the edges vector accordingly. Also removes conflicting edges in a way that ensures the weights are strictly increasing. The maximum length of the paths ending at different nodes is continuously updated, and the final result is the maximum length among these paths.

Steps:

  • Create a vector of maps to represent the directed graph and store the maximum length of paths ending at each node with a specific weight.
  • Iterate through the given edges, calculating the length of the path ending at the starting node with the given weight.
  • For each edge, check if extending the path to the ending node maintains the strictly increasing order of weights.
  • Update the length information for the ending node with the given weight, and remove conflicting edges in a way that ensures weights are strictly increasing.
  • Continuously update the maximum length of paths ending at different nodes.
  • Print the maximum length of the path, considering the specified conditions.

Below is the implementation of the above approach:

C++14




#include <bits/stdc++.h>
using namespace std;
 
vector<map<int, int> > edges;
 
// Function to get the length of the path ending at node 'a'
// with weight 'w'
int getEdgeLength(int a, int w)
{
    auto it = edges[a].lower_bound(w);
    if (it == edges[a].begin())
        return 1;
    it--;
    return (it->second) + 1;
}
 
int main()
{
 
    // Input
    int n = 3, m = 3;
    edges.resize(n + 1);
 
    vector<tuple<int, int, int> > inputEdges
        = { make_tuple(3, 1, 3), make_tuple(1, 2, 1),
            make_tuple(2, 3, 2) };
 
    int maxLength = 0; // Variable to store the maximum
                       // length of the path
 
    for (const auto& edge : inputEdges) {
        int a, b, w;
        tie(a, b, w) = edge;
 
        // Get the length of the path ending at node 'a'
        // with weight 'w'
        int lengthAtA = getEdgeLength(a, w);
 
        // Check if the length of the path ending at node
        // 'b' with weight 'w + 1' is greater than the
        // length obtained for node 'a'. If true, skip this
        // edge.
        if (getEdgeLength(b, w + 1) > lengthAtA) {
            continue;
        }
 
        // Update the length for node 'b' with weight 'w'
        edges[b][w] = max(edges[b][w], lengthAtA);
 
        // Remove all edges in 'b' with weight greater than
        // 'w' and length less than or equal to 'lengthAtA'
        auto it = edges[b].upper_bound(w);
        while (!(it == edges[b].end()
                 || it->second > lengthAtA)) {
            it = edges[b].erase(it);
        }
 
        // Update the maximum length
        maxLength = max(maxLength, lengthAtA);
    }
 
    cout << maxLength
         << "\n"; // Print the maximum length of the path
    return 0;
}


Java




/*code by flutterfly*/
import java.util.*;
 
public class Main {
    static ArrayList<TreeMap<Integer, Integer>> edges;
 
    // Function to get the length of the path ending at node 'a'
    // with weight 'w'
    static int getEdgeLength(int a, int w) {
        TreeMap<Integer, Integer> edgeMap = edges.get(a);
        Integer key = edgeMap.floorKey(w);
        if (key == null) {
            return 1;
        }
        return edgeMap.get(key) + 1;
    }
 
    public static void main(String[] args) {
 
        // Input
        int n = 3, m = 3;
        edges = new ArrayList<>(n + 1);
        for (int i = 0; i <= n; i++) {
            edges.add(new TreeMap<>());
        }
 
        ArrayList<Triple<Integer, Integer, Integer>> inputEdges
                = new ArrayList<>(Arrays.asList(
                new Triple<>(3, 1, 3),
                new Triple<>(1, 2, 1),
                new Triple<>(2, 3, 2)
        ));
 
        int maxLength = 0; // Variable to store the maximum
        // length of the path
 
        for (Triple<Integer, Integer, Integer> edge : inputEdges) {
            int a = edge.first, b = edge.second, w = edge.third;
 
            // Get the length of the path ending at node 'a'
            // with weight 'w'
            int lengthAtA = getEdgeLength(a, w);
 
            // Check if the length of the path ending at node
            // 'b' with weight 'w + 1' is greater than the
            // length obtained for node 'a'. If true, skip this
            // edge.
            if (getEdgeLength(b, w + 1) > lengthAtA) {
                continue;
            }
 
            // Update the length for node 'b' with weight 'w'
            edges.get(b).put(w, Math.max(edges.get(b).getOrDefault(w, 0), lengthAtA));
 
            // Remove all edges in 'b' with weight greater than
            // 'w' and length less than or equal to 'lengthAtA'
            Iterator<Map.Entry<Integer, Integer>> it =
              edges.get(b).tailMap(w, false).entrySet().iterator();
            while (it.hasNext()) {
                Map.Entry<Integer, Integer> entry = it.next();
                if (entry.getValue() <= lengthAtA) {
                    it.remove();
                } else {
                    break;
                }
            }
 
            // Update the maximum length
            maxLength = Math.max(maxLength, lengthAtA);
        }
 
        System.out.println(maxLength
                + "\n"); // Print the maximum length of the path
    }
 
    static class Triple<U, V, W> {
        U first;
        V second;
        W third;
 
        Triple(U first, V second, W third) {
            this.first = first;
            this.second = second;
            this.third = third;
        }
    }
}


Python




#code by flutterfly
from bisect import bisect_right
 
class Triple:
    def __init__(self, first, second, third):
        self.first = first
        self.second = second
        self.third = third
 
 
def get_edge_length(a, w):
    edge_map = edges[a]
    keys = list(edge_map.keys())
    index = bisect_right(keys, w)
    if index == 0:
        return 1
    return edge_map[keys[index - 1]] + 1
 
 
if __name__ == "__main__":
    # Input
    n, m = 3, 3
    edges = [{} for _ in range(n + 1)]
 
    input_edges = [
        Triple(3, 1, 3),
        Triple(1, 2, 1),
        Triple(2, 3, 2)
    ]
 
    max_length = 0  # Variable to store the maximum length of the path
 
    for edge in input_edges:
        a, b, w = edge.first, edge.second, edge.third
 
        # Get the length of the path ending at node 'a'
        # with weight 'w'
        length_at_a = get_edge_length(a, w)
 
        # Check if the length of the path ending at node
        # 'b' with weight 'w + 1' is greater than the
        # length obtained for node 'a'. If true, skip this
        # edge.
        if get_edge_length(b, w + 1) > length_at_a:
            continue
 
        # Update the length for node 'b' with weight 'w'
        edges[b][w] = max(edges[b].get(w, 0), length_at_a)
 
        # Remove all edges in 'b' with weight greater than
        # 'w' and length less than or equal to 'length_at_a'
        for weight in list(edges[b].keys()):
            if weight > w and edges[b][weight] <= length_at_a:
                del edges[b][weight]
            else:
                break
 
        # Update the maximum length
        max_length = max(max_length, length_at_a)
 
    print(max_length)


C#




//code by flutterfly
using System;
using System.Collections.Generic;
using System.Linq;
 
class MainClass
{
    static List<SortedDictionary<int, int>> edges;
 
    static int GetEdgeLength(int a, int w)
    {
        SortedDictionary<int, int> edgeMap = edges[a];
        int index = FindFloorKeyIndex(edgeMap.Keys, w);
        if (index == -1)
        {
            return 1;
        }
        int key = edgeMap.Keys.ElementAt(index);
        return edgeMap[key] + 1;
    }
 
    static int FindFloorKeyIndex(IEnumerable<int> keys, int w)
    {
        int[] keysArray = keys.ToArray();
        int index = Array.BinarySearch(keysArray, w);
        if (index >= 0)
        {
            return index;
        }
        index = ~index - 1;
        return index;
    }
 
    public static void Main(string[] args)
    {
        // Input
        int n = 3;
        edges = new List<SortedDictionary<int, int>>(n + 1);
        for (int i = 0; i <= n; i++)
        {
            edges.Add(new SortedDictionary<int, int>());
        }
 
        List<Triple<int, int, int>> inputEdges = new List<Triple<int, int, int>>
        {
            new Triple<int, int, int>(3, 1, 3),
            new Triple<int, int, int>(1, 2, 1),
            new Triple<int, int, int>(2, 3, 2)
        };
 
        int maxLength = 0; // Variable to store the maximum length of the path
 
        foreach (Triple<int, int, int> edge in inputEdges)
        {
            int a = edge.First, b = edge.Second, w = edge.Third;
 
            // Get the length of the path ending at node 'a'
            // with weight 'w'
            int lengthAtA = GetEdgeLength(a, w);
 
            // Check if the length of the path ending at node
            // 'b' with weight 'w + 1' is greater than the
            // length obtained for node 'a'. If true, skip this
            // edge.
            if (GetEdgeLength(b, w + 1) > lengthAtA)
            {
                continue;
            }
 
            // Update the length for node 'b' with weight 'w'
            if (!edges[b].ContainsKey(w))
            {
                edges[b][w] = 0;
            }
 
            edges[b][w] = Math.Max(edges[b][w], lengthAtA);
 
            // Remove all edges in 'b' with weight greater than
            // 'w' and length less than or equal to 'lengthAtA'
            foreach (var key in new List<int>(edges[b].Keys))
            {
                if (key > w && edges[b][key] <= lengthAtA)
                {
                    edges[b].Remove(key);
                }
                else
                {
                    break;
                }
            }
 
            // Update the maximum length
            maxLength = Math.Max(maxLength, lengthAtA);
        }
 
        Console.WriteLine(maxLength);
    }
 
    class Triple<U, V, W>
    {
        public U First { get; }
        public V Second { get; }
        public W Third { get; }
 
        public Triple(U first, V second, W third)
        {
            First = first;
            Second = second;
            Third = third;
        }
    }
}


Javascript




class Triple {
    constructor(first, second, third) {
        this.first = first;
        this.second = second;
        this.third = third;
    }
}
 
function getEdgeLength(a, w) {
    const edgeMap = edges[a];
    const index = findFloorKeyIndex(Array.from(edgeMap.keys()), w);
    if (index === -1) {
        return 1;
    }
    const key = Array.from(edgeMap.keys())[index];
    return edgeMap.get(key) + 1;
}
 
function findFloorKeyIndex(keys, w) {
    const index = keys.findIndex(key => key >= w);
    if (index !== -1) {
        return index;
    }
    return keys.length - 1;
}
 
// Input
const n = 3, m = 3;
const edges = Array.from({ length: n + 1 }, () => new Map());
 
const inputEdges = [
    new Triple(3, 1, 3),
    new Triple(1, 2, 1),
    new Triple(2, 3, 2)
];
 
let maxLength = 0; // Variable to store the maximum length of the path
 
for (const edge of inputEdges) {
    const a = edge.first, b = edge.second, w = edge.third;
 
    // Get the length of the path ending at node 'a'
    // with weight 'w'
    const lengthAtA = getEdgeLength(a, w);
 
    // Check if the length of the path ending at node
    // 'b' with weight 'w + 1' is greater than the
    // length obtained for node 'a'. If true, skip this
    // edge.
    if (getEdgeLength(b, w + 1) > lengthAtA) {
        continue;
    }
 
    // Update the length for node 'b' with weight 'w'
    edges[b].set(w, Math.max(edges[b].get(w) || 0, lengthAtA));
 
    // Remove all edges in 'b' with weight greater than
    // 'w' and length less than or equal to 'lengthAtA'
    for (const key of Array.from(edges[b].keys())) {
        if (key > w && edges[b].get(key) <= lengthAtA) {
            edges[b].delete(key);
        } else {
            break;
        }
    }
 
    // Update the maximum length
    maxLength = Math.max(maxLength, lengthAtA);
}
 
console.log(maxLength);


Output

2



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



Like Article
Suggest improvement
Share your thoughts in the comments

Similar Reads