Open In App

Shortest path with maximum score and fixed start/end node

Last Updated : 23 Nov, 2023
Improve
Improve
Like Article
Like
Save
Share
Report

Given a graph with N nodes and M edges with array A[] and integer C, the task is to find the maximum score. If visiting node i gives A[i] points for all i from 1 to N. It is necessary to start the traversal from node 1 and end the traversal on node 1. The cost of traversal is C * T2 where T is the distance traveled.

Examples:

Input: A[] = {0, 10, 20}, edges[][2] = { {1, 2}, {2, 3}, {3, 1} }, C = 1
Output: 24
Explanation:

  • The optimal traversal is 1 -> 2 -> 3 -> 1 -> 2 -> 3 -> 1
  • T = Total Distance travelled = 6 
  • The cost is 10 (1 -> 2) + 20 (2 -> 3) + 0 (3 -> 1) + 10 (1 -> 2)  + 20 (2 -> 3) + 0 (3 -> 1) – C * T2 = 60 – C * T2 = 60 – 1 * 62 = 24

     

example 1 :

Input: A[] = {0, 10, 20}, edges[][2] = { {1, 2}, {2, 3}, {3, 1} }, C= 100
Output: 0
Explanation: It’s optimal not to traverse at all.

Naive approach: The basic way to solve the problem is as follows:

The basic way to solve this problem is to generate all possible combinations by using a recursive approach.

Time Complexity: O(N!)
Auxiliary Space: O(1)

Efficient Approach:  The above approach can be optimized based on the following idea:

Dynamic programming can be used to solve this problem

  • dp[i][j] = the maximum score on traversing node i’th time ending on node j.
  • recurrence relation: dp[curTime][u] = max(dp[curTime][u], dp[curTime – 1][i] + A[u]);

Follow the steps below to solve the problem:

  • Declare a 2d array dp[maxTime][N] with all values initialized to -1 indicating no node is visited yet.
  • Base case dp[0][0] = 0, if we do not travel at all we get 0 coins.
  • Initialize the answer variable to keep track of the max score.
  • Iterate on all and for each day iterate on all nodes.
  • At the end of each day keep track of the maximum value possible.
  • Finally, return the answer.

Below is the implementation of the above approach:

C++




// C++ code to implement the approach
#include <bits/stdc++.h>
using namespace std;
 
// Function to calculate maximum coins
// during trips
void maximumCoins(int A[], int N, int edg[][2], int M,
                  int C)
{
 
    // Adjecency list
    vector<vector<int> > adj(N);
 
    for (int i = 0; i < M; i++) {
 
        // Travel from edg[i][0]
        // to edg[i][1]
        adj[--edg[i][0]].push_back(--edg[i][1]);
    }
 
    // dp table initialized with -1
    // indicating not visited
    vector<vector<int> > dp(1001, vector<int>(N, -1));
 
    // Base case
    dp[0][0] = 0;
 
    int ans = 0;
 
    // Simulating time from 0 to 1000
    for (int curTime = 0; curTime < 1000; curTime++) {
 
        // At each unit time iterate
        // on each node
        for (int i = 0; i < N; i++) {
 
            // If dp[d][i] == -1 then the
            // node can't be visited
            if (dp[curTime][i] != -1) {
                for (int u : adj[i]) {
 
                    // dp[curTime + 1][u]
                    // is max(current coins
                    // earned, previous
                    // node's earnings +
                    // current node's
                    // earnings)
                    dp[curTime + 1][u]
                        = max(dp[curTime + 1][u],
                              dp[curTime][i] + A[u]);
                }
            }
        }
        ans = max(ans, (dp[curTime][0]
                        - (C * curTime * curTime)));
    }
 
    cout << ans << "\n";
}
 
// Driver Code
int main()
{
 
    // Input 1
    int A[] = { 0, 10, 20 },
        edges[][2] = { { 1, 2 }, { 2, 3 }, { 3, 1 } },
        C = 1;
    int N = sizeof(A) / sizeof(A[0]);
    int M = 3;
 
    // Function Call
    maximumCoins(A, N, edges, M, C);
 
    // Input 2
    int A1[] = { 0, 10, 20 },
        edges1[][2] = { { 1, 2 }, { 2, 3 }, { 3, 1 } },
        C1 = 10;
    int N1 = sizeof(A1) / sizeof(A1[0]);
    int M1 = 3;
 
    // Function Call
    maximumCoins(A1, N1, edges1, M1, C1);
    return 0;
}


Java




import java.util.*;
 
public class Main {
 
    // Function to calculate maximum coins during trips
    public static void
    maximumCoins(int[] A, int N, int[][] edg, int M, int C)
    {
 
        // Adjacency list
        ArrayList<ArrayList<Integer> > adj
            = new ArrayList<ArrayList<Integer> >();
        for (int i = 0; i < N; i++) {
            adj.add(new ArrayList<Integer>());
        }
 
        for (int i = 0; i < M; i++) {
 
            // Travel from edg[i][0] to edg[i][1]
            adj.get(edg[i][0] - 1).add(edg[i][1] - 1);
        }
 
        // dp table initialized with -1 indicating not
        // visited
        int[][] dp = new int[1001][N];
        for (int i = 0; i < 1001; i++) {
            Arrays.fill(dp[i], -1);
        }
 
        // Base case
        dp[0][0] = 0;
 
        int ans = 0;
 
        // Simulating time from 0 to 1000
        for (int curTime = 0; curTime < 1000; curTime++) {
 
            // At each unit time iterate on each node
            for (int i = 0; i < N; i++) {
 
                // If dp[d][i] == -1 then the node can't be
                // visited
                if (dp[curTime][i] != -1) {
                    for (int u : adj.get(i)) {
 
                        // dp[curTime + 1][u] is max(current
                        // coins earned, previous node's
                        // earnings + current node's
                        // earnings)
                        dp[curTime + 1][u] = Math.max(
                            dp[curTime + 1][u],
                            dp[curTime][i] + A[u]);
                    }
                }
            }
            ans = Math.max(
                ans,
                (dp[curTime][0] - (C * curTime * curTime)));
        }
 
        System.out.println(ans);
    }
 
    // Driver Code
    public static void main(String[] args)
    {
 
        // Input 1
        int[] A = { 0, 10, 20 };
        int[][] edges = { { 1, 2 }, { 2, 3 }, { 3, 1 } };
        int C = 1;
        int N = A.length;
        int M = 3;
 
        // Function Call
        maximumCoins(A, N, edges, M, C);
 
        // Input 2
        int[] A1 = { 0, 10, 20 };
        int[][] edges1 = { { 1, 2 }, { 2, 3 }, { 3, 1 } };
        int C1 = 10;
        int N1 = A1.length;
        int M1 = 3;
 
        // Function Call
        maximumCoins(A1, N1, edges1, M1, C1);
    }
}
 
// This code is contributed by Prajwal Kandekar


Python3




# Python code to implement the approach
 
# Function to calculate maximum coins
# during trips
 
 
def maximumCoins(A, N, edg, M, C):
 
    # Adjacency list
    adj = [[] for i in range(N)]
 
    for i in range(M):
 
        # Travel from edg[i][0]
        # to edg[i][1]
        adj[edg[i][0]-1].append(edg[i][1]-1)
 
    # dp table initialized with -1
    # indicating not visited
    dp = [[-1 for i in range(N)] for j in range(1001)]
 
    # Base case
    dp[0][0] = 0
 
    ans = 0
 
    # Simulating time from 0 to 1000
    for curTime in range(1000):
 
        # At each unit time iterate
        # on each node
        for i in range(N):
 
            # If dp[d][i] == -1 then the
            # node can't be visited
            if dp[curTime][i] != -1:
                for u in adj[i]:
 
                    # dp[curTime + 1][u]
                    # is max(current coins
                    # earned, previous
                    # node's earnings +
                    # current node's
                    # earnings)
                    dp[curTime + 1][u] = max(dp[curTime + 1]
                                             [u], dp[curTime][i] + A[u])
 
        ans = max(ans, (dp[curTime][0] - (C * curTime * curTime)))
 
    print(ans)
 
 
# Driver Code
if __name__ == '__main__':
 
    # Input 1
    A = [0, 10, 20]
    edges = [[1, 2], [2, 3], [3, 1]]
    C = 1
    N = len(A)
    M = 3
 
    # Function Call
    maximumCoins(A, N, edges, M, C)
 
    # Input 2
    A1 = [0, 10, 20]
    edges1 = [[1, 2], [2, 3], [3, 1]]
    C1 = 10
    N1 = len(A1)
    M1 = 3
 
    # Function Call
    maximumCoins(A1, N1, edges1, M1, C1)


C#




using System;
using System.Collections.Generic;
 
class Program {
    // Function to calculate maximum coins during trips
    public static void
    maximumCoins(int[] A, int N, int[][] edg, int M, int C)
    {
 
        // Adjacency list
        List<List<int> > adj = new List<List<int> >();
        for (int i = 0; i < N; i++) {
            adj.Add(new List<int>());
        }
 
        for (int i = 0; i < M; i++) {
 
            // Travel from edg[i][0] to edg[i][1]
            adj[edg[i][0] - 1].Add(edg[i][1] - 1);
        }
 
        // dp table initialized with -1 indicating not
        // visited
        int[][] dp = new int[1001][];
        for (int i = 0; i < 1001; i++) {
            dp[i] = new int[N];
            for (int j = 0; j < N; j++) {
                dp[i][j] = -1;
            }
        }
 
        // Base case
        dp[0][0] = 0;
 
        int ans = 0;
 
        // Simulating time from 0 to 1000
        for (int curTime = 0; curTime < 1000; curTime++) {
 
            // At each unit time iterate on each node
            for (int i = 0; i < N; i++) {
 
                // If dp[d][i] == -1 then the node can't be
                // visited
                if (dp[curTime][i] != -1) {
                    foreach(int u in adj[i])
                    {
 
                        // dp[curTime + 1][u] is max(current
                        // coins earned, previous node's
                        // earnings + current node's
                        // earnings)
                        dp[curTime + 1][u] = Math.Max(
                            dp[curTime + 1][u],
                            dp[curTime][i] + A[u]);
                    }
                }
            }
            ans = Math.Max(
                ans,
                (dp[curTime][0] - (C * curTime * curTime)));
        }
 
        Console.WriteLine(ans);
    }
 
    // Driver Code
    public static void Main(string[] args)
    {
 
        // Input 1
        int[] A = { 0, 10, 20 };
        int[][] edges
            = { new int[] { 1, 2 }, new int[] { 2, 3 },
                new int[] { 3, 1 } };
        int C = 1;
        int N = A.Length;
        int M = 3;
 
        // Function Call
        maximumCoins(A, N, edges, M, C);
 
        // Input 2
        int[] A1 = { 0, 10, 20 };
        int[][] edges1
            = { new int[] { 1, 2 }, new int[] { 2, 3 },
                new int[] { 3, 1 } };
        int C1 = 10;
        int N1 = A1.Length;
        int M1 = 3;
 
        // Function Call
        maximumCoins(A1, N1, edges1, M1, C1);
    }
}
 
// This code is contributed by Tapesh(tapeshdua420)


Javascript




// Function to calculate maximum coins during trips
function maximumCoins(A, N, edg, M, C) {
    // Adjacency list
let adj = [];
for (let i = 0; i < N; i++) {
    adj.push([]);
}
 
for (let i = 0; i < M; i++) {
    // Travel from edg[i][0] to edg[i][1]
    adj[edg[i][0] - 1].push(edg[i][1] - 1);
}
 
// dp table initialized with -1 indicating not visited
let dp = [];
for (let i = 0; i < 1001; i++) {
    let temp = [];
    for (let j = 0; j < N; j++) {
        temp.push(-1);
    }
    dp.push(temp);
}
 
// Base case
dp[0][0] = 0;
 
let ans = 0;
 
// Simulating time from 0 to 1000
for (let curTime = 0; curTime < 1000; curTime++) {
 
    // At each unit time iterate on each node
    for (let i = 0; i < N; i++) {
 
        // If dp[d][i] == -1 then the node can't be visited
        if (dp[curTime][i] != -1) {
            for (let j = 0; j < adj[i].length; j++) {
 
                let u = adj[i][j];
 
                // dp[curTime + 1][u] is max(current coins earned, previous
                // node's earnings + current node's earnings)
                dp[curTime + 1][u] = Math.max(dp[curTime + 1][u], dp[curTime][i] + A[u]);
            }
        }
    }
 
    ans = Math.max(ans, (dp[curTime][0] - (C * curTime * curTime)));
}
 
console.log(ans);
}
 
// Driver Code
let A = [0, 10, 20];
let edges = [[1, 2], [2, 3], [3, 1]];
let C = 1;
let N = A.length;
let M = 3;
 
// Function Call
maximumCoins(A, N, edges, M, C);
 
let A1 = [0, 10, 20];
let edges1 = [[1, 2], [2, 3], [3, 1]];
let C1 = 10;
let N1 = A1.length;
let M1 = 3;
 
// Function Call
maximumCoins(A1, N1, edges1, M1, C1);


Output

24
0








Time Complexity: O((N + M) * D)
Auxiliary Space: O(N * D) where D is the maximum number of nodes visited.

Efficient approach : Space optimization

In previous approach the dp[i][j] is depend upon the current and previous row of 2D matrix. So to optimize space we use two vectors dp1 and dp2 that keep track of current and previous row of DP.

Implementation Steps:

  • Initialize 2 vectors dp1 and dp2 with -1 of size N to keep track of only previous and current row of Dp matrix.
  • Initialize dp1 with the base case. and a variable ans to update the dp2 with current value.
  • Now iterative over subproblems and get the current computation.
  • Now compute the current value by the help of dp1 vector and store that value in dp2.
  • After every iteration store values of dp2 vector in dp1 vector for further iteration.
  • At last print the ans.

C++




#include <bits/stdc++.h>
using namespace std;
 
// Function to calculate maximum coins
// during trips
void maximumCoins(int A[], int N, int edg[][2], int M, int C) {
 
    vector<vector<int>> adj(N);
 
    for (int i = 0; i < M; i++) {
        adj[--edg[i][0]].push_back(--edg[i][1]);
    }
 
    vector<int> dp1(N, -1);  // Current time step DP
    vector<int> dp2(N, -1);  // Next time step DP
 
    // Base case
    dp1[0] = 0;
 
    int ans = 0;
     
      // iterate over subproblems
    for (int curTime = 0; curTime < 1000; curTime++) {
        for (int i = 0; i < N; i++) {
            if (dp1[i] != -1) {
                for (int u : adj[i]) {
                    dp2[u] = max(dp2[u], dp1[i] + A[u]);
                }
            }
        }
       
        ans = max(ans, (dp1[0] - (C * curTime * curTime)));
 
        // Swap dp1 and dp2 for the next time step
        swap(dp1, dp2);
        fill(dp2.begin(), dp2.end(), -1);  // Reset dp2 to -1
    }
 
    cout << ans << "\n";
}
 
int main() {
 
    // Input 1
    int A[] = { 0, 10, 20 },
        edges[][2] = { { 1, 2 }, { 2, 3 }, { 3, 1 } },
        C = 1;
    int N = sizeof(A) / sizeof(A[0]);
    int M = 3;
 
    // Function Call
    maximumCoins(A, N, edges, M, C);
 
    // Input 2
    int A1[] = { 0, 10, 20 },
        edges1[][2] = { { 1, 2 }, { 2, 3 }, { 3, 1 } },
        C1 = 10;
    int N1 = sizeof(A1) / sizeof(A1[0]);
    int M1 = 3;
 
    // Function Call
    maximumCoins(A1, N1, edges1, M1, C1);
    return 0;
}


Java




import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
 
public class MaximumCoinsProgram {
 
    // Function to calculate maximum coins during trips
    static void maximumCoins(int[] A, int N, int[][] edg, int M, int C) {
 
        List<List<Integer>> adj = new ArrayList<>();
 
        for (int i = 0; i < N; i++) {
            adj.add(new ArrayList<>());
        }
 
        for (int i = 0; i < M; i++) {
            adj.get(edg[i][0] - 1).add(edg[i][1] - 1);
        }
 
        int[] dp1 = new int[N];
        Arrays.fill(dp1, -1);
 
        int[] dp2 = new int[N];
        Arrays.fill(dp2, -1);
 
        // Base case
        dp1[0] = 0;
 
        int ans = 0;
 
        // Iterate over subproblems
        for (int curTime = 0; curTime < 1000; curTime++) {
            for (int i = 0; i < N; i++) {
                if (dp1[i] != -1) {
                    for (int u : adj.get(i)) {
                        dp2[u] = Math.max(dp2[u], dp1[i] + A[u]);
                    }
                }
            }
 
            ans = Math.max(ans, (dp1[0] - (C * curTime * curTime)));
 
            // Swap dp1 and dp2 for the next time step
            int[] temp = dp1;
            dp1 = dp2;
            dp2 = temp;
 
            Arrays.fill(dp2, -1); // Reset dp2 to -1
        }
 
        System.out.println(ans);
    }
 
    public static void main(String[] args) {
 
        // Input 1
        int[] A = {0, 10, 20};
        int[][] edges = {{1, 2}, {2, 3}, {3, 1}};
        int C = 1;
        int N = A.length;
        int M = 3;
 
        // Function Call
        maximumCoins(A, N, edges, M, C);
 
        // Input 2
        int[] A1 = {0, 10, 20};
        int[][] edges1 = {{1, 2}, {2, 3}, {3, 1}};
        int C1 = 10;
        int N1 = A1.length;
        int M1 = 3;
 
        // Function Call
        maximumCoins(A1, N1, edges1, M1, C1);
    }
}


Python3




def maximumCoins(A, N, edg, M, C):
    adj = [[] for _ in range(N)]
 
    for i in range(M):
        adj[edg[i][0] - 1].append(edg[i][1] - 1)
 
    dp1 = [-1] * # Current time step DP
    dp2 = [-1] * # Next time step DP
 
    # Base case
    dp1[0] = 0
 
    ans = 0
 
    # Iterate over subproblems
    for curTime in range(1000):
        for i in range(N):
            if dp1[i] != -1:
                for u in adj[i]:
                    dp2[u] = max(dp2[u], dp1[i] + A[u])
 
        ans = max(ans, (dp1[0] - (C * curTime * curTime)))
 
        # Swap dp1 and dp2 for the next time step
        dp1, dp2 = dp2, [-1] * N
 
    print(ans)
# Driver code
# Input 1
A = [0, 10, 20]
edges = [[1, 2], [2, 3], [3, 1]]
C = 1
N = len(A)
M = 3
 
# Function Call
maximumCoins(A, N, edges, M, C)
 
# Input 2
A1 = [0, 10, 20]
edges1 = [[1, 2], [2, 3], [3, 1]]
C1 = 10
N1 = len(A1)
M1 = 3
 
# Function Call
maximumCoins(A1, N1, edges1, M1, C1)


C#




using System;
using System.Collections.Generic;
 
class Program
{
    // Function to calculate maximum coins during trips
    static void MaximumCoins(int[] A, int N, int[][] edg, int M, int C)
    {
        List<List<int>> adj = new List<List<int>>(N);
 
        for (int i = 0; i < N; i++)
        {
            adj.Add(new List<int>());
        }
 
        for (int i = 0; i < M; i++)
        {
            adj[edg[i][0] - 1].Add(edg[i][1] - 1);
        }
 
        int[] dp1 = new int[N];
        int[] dp2 = new int[N];
 
        for (int i = 0; i < N; i++)
        {
            dp1[i] = -1;
            dp2[i] = -1;
        }
 
        // Base case
        dp1[0] = 0;
 
        int ans = 0;
 
        // Iterate over subproblems
        for (int curTime = 0; curTime < 1000; curTime++)
        {
            for (int i = 0; i < N; i++)
            {
                if (dp1[i] != -1)
                {
                    foreach (int u in adj[i])
                    {
                        dp2[u] = Math.Max(dp2[u], dp1[i] + A[u]);
                    }
                }
            }
 
            ans = Math.Max(ans, (dp1[0] - (C * curTime * curTime)));
 
            // Swap dp1 and dp2 for the next time step
            int[] temp = dp1;
            dp1 = dp2;
            dp2 = temp;
 
            for (int i = 0; i < N; i++)
            {
                dp2[i] = -1;
            }
        }
 
        Console.WriteLine(ans);
    }
 
    static void Main(string[] args)
    {
        // Input 1
        int[] A = { 0, 10, 20 };
        int[][] edges = { new int[] { 1, 2 }, new int[] { 2, 3 }, new int[] { 3, 1 } };
        int C = 1;
        int N = A.Length;
        int M = 3;
 
        // Function Call
        MaximumCoins(A, N, edges, M, C);
 
        // Input 2
        int[] A1 = { 0, 10, 20 };
        int[][] edges1 = { new int[] { 1, 2 }, new int[] { 2, 3 }, new int[] { 3, 1 } };
        int C1 = 10;
        int N1 = A1.Length;
        int M1 = 3;
 
        // Function Call
        MaximumCoins(A1, N1, edges1, M1, C1);
    }
}


Javascript




// Javascript code
 
function maximumCoins(A, N, edg, M, C) {
    let adj = Array.from({ length: N }, () => []);
 
    for (let i = 0; i < M; i++) {
        adj[edg[i][0] - 1].push(edg[i][1] - 1);
    }
 
    let dp1 = Array(N).fill(-1); // Current time step DP
    let dp2 = Array(N).fill(-1); // Next time step DP
 
    // Base case
    dp1[0] = 0;
 
    let ans = 0;
 
    // iterate over subproblems
    for (let curTime = 0; curTime < 1000; curTime++) {
        for (let i = 0; i < N; i++) {
            if (dp1[i] !== -1) {
                for (let u of adj[i]) {
                    dp2[u] = Math.max(dp2[u], dp1[i] + A[u]);
                }
            }
        }
 
        ans = Math.max(ans, dp1[0] - C * curTime * curTime);
 
        // Swap dp1 and dp2 for the next time step
        [dp1, dp2] = [dp2, Array(N).fill(-1)]; // Reset dp2 to -1
    }
 
    console.log(ans);
}
 
// Input 1
let A = [0, 10, 20];
let edges = [[1, 2], [2, 3], [3, 1]];
let C = 1;
let N = A.length;
let M = 3;
 
// Function Call
maximumCoins(A, N, edges, M, C);
 
// Input 2
let A1 = [0, 10, 20];
let edges1 = [[1, 2], [2, 3], [3, 1]];
let C1 = 10;
let N1 = A1.length;
let M1 = 3;
 
// Function Call
maximumCoins(A1, N1, edges1, M1, C1);
 
 
// This code is contributed by guptapratik


Output

24
0

Time Complexity: O(1000 * N * M), where N is the number of nodes, and M is the number of edges in the graph.

Auxiliary Space: O(N + M)

Related Articles:



Like Article
Suggest improvement
Share your thoughts in the comments

Similar Reads