Maximize the value of F(N) = max( N, F(N /2) + F(N / 3) + F(N / 4)) for any given integer
Given an integer N, the task is to find the maximum value of function F(n) given by F(N) = max(N, F(N /2) + F(N / 3) + F(N / 4)).
Examples:
Input: N = 3
Output: 3
Explanation:
F(3) = max(3, F(1) + F(1) + F(0)) as F(0) = 0 and F(1) = 1
F(3) = max(3, 1 + 1+ 0)
F(3) = max(3, 2)
Hence, the maximum value of F(3) is 3.
Input: N = 12
Output:13
Explanation:
F(12) = max(12, F(6) + F(4) + F(3))
F(6) = max(6, F(3) + F(2) + F(1))
F(3) = max(3, F(1) + F(1) + F(0)) as F(0) = 0 and F(1) = 1
F(3) = max(3, 1 + 1+ 0)
F(3) = max(3, 2) = 3
F(2) = max(2, F(1) + F(0) + F(0))
F(2) = max(2,1 + 0 + 0) = 2
F(4) = max(4, F(2) + F(1) + F(1))
F(4) = max(4, 2 + 1 + 1) = 4
F(6) = max(6, 3 + 2 + 1) = 6
Now, F(12) = max(12, 6 + 4 + 3)
F(12) = max(12, 13)
Hence, the maximum value of F(12) is 13.
Naive Approach: The simplest approach is to use recursion to calculate the value of F(N). In each step, call three recursive calls for each of the values N/2, N/3, and N/4, and then each recursive call returns the value of the maximum of N and the sum of values returned by these recursive calls. After all, the recursive call ends print the value as the result.
Time Complexity: O(3N)
Auxiliary Space: O(1)
Dynamic Programming using Bottom-Down Approach: The recursive calls in the above can also be reduced using an auxiliary array dp[] and calculate the value of each state in the bottom-up approach. Below are the steps:
- Create an auxiliary array dp[] of size N.
- Initialize the state 0 and 1 as dp[0] = 0 and dp[1] = 1.
- Traverse the array dp[] over the range [2, N] and update each state as:
dp[i] = max(i, dp[i/2] + dp[i/3] + dp[i/4])
- Print the value of dp[N] after the above steps as the result.
Below is the implementation of the above approach:
C++
#include <bits/stdc++.h>
using namespace std;
void build( int dp[], int N)
{
dp[0] = 0;
dp[1] = 1;
for ( int i = 2; i <= N; i++) {
dp[i] = max(i, dp[i / 2]
+ dp[i / 3]
+ dp[i / 4]);
}
}
int maxValue( int N)
{
int dp[N + 1];
build(dp, N);
cout << dp[N];
}
int main()
{
int N = 12;
maxValue(N);
return 0;
}
|
Java
import java.util.*;
class GFG{
static void build( int dp[], int N)
{
dp[ 0 ] = 0 ;
dp[ 1 ] = 1 ;
for ( int i = 2 ; i <= N; i++)
{
dp[i] = Math.max(i, dp[i / 2 ] +
dp[i / 3 ] +
dp[i / 4 ]);
}
}
static void maxValue( int N)
{
int dp[] = new int [N + 1 ];
build(dp, N);
System.out.println(dp[N]);
}
public static void main(String[] args)
{
int N = 12 ;
maxValue(N);
}
}
|
Python3
def build(dp, N):
dp[ 0 ] = 0
dp[ 1 ] = 1
for i in range ( 2 , N + 1 ):
dp[i] = max (i, dp[i / / 2 ] +
dp[i / / 3 ] +
dp[i / / 4 ])
def maxValue(N):
dp = [ 0 ] * (N + 1 )
build(dp, N)
print (dp[N], end = "")
if __name__ = = '__main__' :
N = 12
maxValue(N)
|
C#
using System;
class GFG{
static void build( int []dp,
int N)
{
dp[0] = 0;
dp[1] = 1;
for ( int i = 2; i <= N; i++)
{
dp[i] = Math.Max(i, dp[i / 2] +
dp[i / 3] +
dp[i / 4]);
}
}
static void maxValue( int N)
{
int []dp = new int [N + 1];
build(dp, N);
Console.WriteLine(dp[N]);
}
public static void Main(String[] args)
{
int N = 12;
maxValue(N);
}
}
|
Javascript
<script>
function build( dp, N)
{
dp[0] = 0;
dp[1] = 1;
for ( var i = 2; i <= N; i++)
{
dp[i] = Math.max(i, dp[(Math.floor(i / 2))] + dp[(Math.floor(i / 3))] +
dp[(Math.floor(i / 4))]);
}
}
function maxValue( N)
{
var dp = [] ;
build(dp, N);
document.write(dp[N]);
}
var N = 12;
maxValue(N);
</script>
|
Time Complexity: O(N)
Space Complexity: O(N)
Dynamic Programming using Top-Down Approach: As in the above approach there are many Overlapping Subproblems for each recursive call. Therefore, to optimize the above approach, the idea is to use the auxiliary space map to store the value calculated in each recursive call and return the recurring stored state. Below are the steps:
- Initialize a map Map to store the value calculated at each recursive call.
- Base Case: If the value of N is 0 or 1 then the result is 0 and 1 respectively. Also, if there is any previously calculated state then return that value as:
>Base Case:
if(N <= 1) {
return N;
}
Memoized State:
if(Map.find(N) != Map.end()) {
return Map[N];
}
- Recursive Call: If the base case is not met, then find the value of the current state by recursively calling for each state as:
result = max(N, recursive_function(N/2) + recursive_function(N/3) + recursive_function(N/4))
- Return Statement: At each recursive call(except the base case), store the current state calculated in the above step in the map and return the value calculated as the result for the current state.
Map[N] = result;
return result;
- After the above steps, print the value return to the end of all the recursive calls.
Below is the implementation of the above approach:
C++
#include <bits/stdc++.h>
using namespace std;
map< int , int > mp;
int maxValue( int N)
{
if (N <= 1)
return N;
if (mp[N] != 0)
return mp[N];
int ans = max(N, maxValue(N / 2)
+ maxValue(N / 3)
+ maxValue(N / 4));
mp[N] = ans;
return ans;
}
void maxValueUtil( int N)
{
int result = maxValue(N);
cout << result;
}
int main()
{
int N = 12;
maxValueUtil(N);
return 0;
}
|
Java
import java.util.*;
import java.lang.*;
class GFG{
static Map<Integer, Integer> mp = new HashMap<>();
static int maxValue( int N)
{
if (N <= 1 )
return N;
if (mp.containsKey(N))
return mp.get(N);
int ans = Math.max(N, maxValue(N / 2 ) +
maxValue(N / 3 ) +
maxValue(N / 4 ));
mp.put(N, ans);
return ans;
}
static void maxValueUtil( int N)
{
int result = maxValue(N);
System.out.print(result);
}
public static void main (String[] args)
{
int N = 12 ;
maxValueUtil(N);
}
}
|
Python3
mp = {}
def maxValue(N):
if (N < = 1 ):
return N
if (N in mp):
return mp[N]
ans = ( max (N, maxValue(N / / 2 ) +
maxValue(N / / 3 ) +
maxValue(N / / 4 )))
if (N in mp):
mp[N] = ans
else :
mp[N] = mp.get(N, 0 ) + ans
return ans
def maxValueUtil(N):
result = maxValue(N)
print (result)
if __name__ = = '__main__' :
N = 12
maxValueUtil(N)
|
C#
using System;
using System.Collections.Generic;
class GFG{
static Dictionary< int ,
int > mp = new Dictionary< int ,
int >();
static int maxValue( int N)
{
if (N <= 1)
return N;
if (mp.ContainsKey(N))
return mp[N];
int ans = Math.Max(N, maxValue(N / 2) +
maxValue(N / 3) +
maxValue(N / 4));
mp.Add(N, ans);
return ans;
}
static void maxValueUtil( int N)
{
int result = maxValue(N);
Console.Write(result);
}
public static void Main(String[] args)
{
int N = 12;
maxValueUtil(N);
}
}
|
Javascript
<script>
let mp= new Map;
function maxValue( N)
{
if (N <= 1)
return N;
if (mp[N])
return mp[N];
let ans = Math.max(N, maxValue(Math.floor(N / 2) )
+ maxValue(Math.floor(N / 3))
+ maxValue(Math.floor(N / 4)));
mp[N] = ans;
return ans;
}
function maxValueUtil( N)
{
let result = maxValue(N);
document.write(result);
}
let N = 12;
maxValueUtil(N);
</script>
|
Time Complexity: O(log N)
Auxiliary Space: O(log N)
Last Updated :
24 Mar, 2023
Like Article
Save Article
Share your thoughts in the comments
Please Login to comment...