Maximum multiple of D from K-sized subset sums from given Array
Last Updated :
11 Nov, 2023
Given an integer array A[] of size N and two integers K, D. A list or superset of all possible subset sums of size K is made from the given array, the task is to find the largest multiple of D from this list or superset. If there exists no multiple, return -1 as the answer.
Examples:
Input: N = 4, K = 2, D = 2, A[] = [1, 2, 3, 4]
Output: 6
Explanation: All possible sums are [3, 4, 5, 5, 6, 7]. The greatest multiple of 2 is 6.
Input: N = 4, K = 1, D = 3, A[] = [1, 5, 7, 8]
Output: -1
Explanation: All possible sums are [1, 5, 7, 8]. No multiple of 3 exists, hence return -1 as the answer.
Approach: To solve the problem using Recursive Top-Down Dp follow the below idea::
The main idea behind this solution is to break down the problem into smaller subproblems by considering each element of the array A. At each index i of the array A, we have two options – either include the element in one of the K subsets or exclude it. Thus, we can represent the problem as a tree of decisions, with each node representing the inclusion or exclusion of an element.
Steps that were to follow to implement the above approach:
- The countSubsetsRec function recursively calculates the maximum sum of a subset of a that contains exactly j elements and has a sum that is a multiple of D, where a is the input array of size N. The function takes the current index i, the number of chosen elements j, the current sum modulo D k, and the memoization table dp.
- The base case is when we have processed all N elements. If we have chosen exactly K elements and the sum is a multiple of D, we return 0, as we have found a valid subset. Otherwise, we return -INF to indicate that this state is impossible.
- We then check if the current state is already computed in the memoization table dp. If it is, we return the stored value.
- Otherwise, we calculate the maximum sum of a subset that contains exactly j elements and has a sum that is a multiple of D using the two possible transitions –
- one where we do not choose the current element and,
- one where we choose it.
- We take the maximum of these two transitions.
- Finally, we memoize the current state and return the result.
- The countSubsets function initializes the memoization table dp and calls countSubsetsRec with the initial parameters.
Below is the code to implement the above approach:
C++
#include <bits/stdc++.h>
using namespace std;
long long
countSubsetsRec( int i, int j, int k, int N, int K, int D,
vector< int >& a,
vector<vector<vector< long long > > >& dp)
{
if (i == N) {
if (j == K && k == 0) {
return 0;
}
else {
return INT_MIN;
}
}
if (dp[i][j][k] != -1) {
return dp[i][j][k];
}
long long ans
= countSubsetsRec(i + 1, j, k, N, K, D, a, dp);
if (j != K) {
ans = max(ans, countSubsetsRec(i + 1, j + 1,
(k + a[i]) % D, N, K,
D, a, dp)
+ a[i]);
}
dp[i][j][k] = ans;
return ans;
}
long long countSubsets( int N, int K, int D, vector< int > a)
{
vector<vector<vector< long long > > > dp(
N + 1, vector<vector< long long > >(
K + 1, vector< long long >(D, -1)));
return countSubsetsRec(0, 0, 0, N, K, D, a, dp);
}
int main()
{
int N = 4, K = 2, D = 2;
vector< int > a = { 1, 2, 3, 4 };
if (countSubsets(N, K, D, a) < 0) {
cout << -1;
return 0;
}
cout << countSubsets(N, K, D, a);
return 0;
}
|
Java
import java.io.*;
import java.util.*;
class GFG {
static long countSubsetsRec( int i, int j, int k, int N,
int K, int D, int [] a,
long [][][] dp)
{
if (i == N) {
if (j == K && k == 0 ) {
return 0 ;
}
else {
return Integer.MIN_VALUE;
}
}
if (dp[i][j][k] != - 1 ) {
return dp[i][j][k];
}
long ans
= countSubsetsRec(i + 1 , j, k, N, K, D, a, dp);
if (j != K) {
ans = Math.max(ans,
countSubsetsRec(i + 1 , j + 1 ,
(k + a[i]) % D,
N, K, D, a, dp)
+ a[i]);
}
dp[i][j][k] = ans;
return ans;
}
static long countSubsets( int N, int K, int D, int [] a)
{
long [][][] dp = new long [N + 1 ][K + 1 ][D];
for ( int i = 0 ; i <= N; i++) {
for ( int j = 0 ; j <= K; j++) {
Arrays.fill(dp[i][j], - 1 );
}
}
long ans = countSubsetsRec( 0 , 0 , 0 , N, K, D, a, dp);
if (ans < 0 ) {
return - 1 ;
}
else {
return ans;
}
}
public static void main(String[] args)
{
int N = 4 , K = 2 , D = 2 ;
int [] a = { 1 , 2 , 3 , 4 };
if (countSubsets(N, K, D, a) < 0 ) {
System.out.println( "-1" );
return ;
}
System.out.println(countSubsets(N, K, D, a));
}
}
|
Python3
def countSubsetsRec(i, j, k, N, K, D, a, dp):
if i = = N:
if j = = K and k = = 0 :
return 0
else :
return float ( '-inf' )
if dp[i][j][k] ! = - 1 :
return dp[i][j][k]
ans = countSubsetsRec(i + 1 , j, k, N, K, D, a, dp)
if j ! = K:
ans = max (ans, countSubsetsRec(i + 1 , j + 1 , (k + a[i]) % D, N, K, D, a, dp) + a[i])
dp[i][j][k] = ans
return ans
def countSubsets(N, K, D, a):
dp = [[[ - 1 for i in range (D)] for j in range (K + 1 )] for k in range (N + 1 )]
ans = countSubsetsRec( 0 , 0 , 0 , N, K, D, a, dp)
if ans < 0 :
return - 1
else :
return ans
if __name__ = = '__main__' :
N = 4
K = 2
D = 2
a = [ 1 , 2 , 3 , 4 ]
print (countSubsets(N, K, D, a))
|
C#
using System;
class GFG {
static long countSubsets( int N, int K, int D, int [] a)
{
long [, , ] dp = new long [N + 1, K + 1, D];
for ( int i = 0; i <= N; i++) {
for ( int j = 0; j <= K; j++) {
for ( int k = 0; k < D; k++) {
dp[i, j, k] = -1;
}
}
}
long ans = countSubsetsRec(0, 0, 0, N, K, D, a, dp);
if (ans < 0) {
return -1;
}
else {
return ans;
}
}
static long countSubsetsRec( int i, int j, int k, int N,
int K, int D, int [] a,
long [, , ] dp)
{
if (i == N) {
if (j == K && k == 0) {
return 0;
}
else {
return Int32.MinValue;
}
}
if (dp[i, j, k] != -1) {
return dp[i, j, k];
}
long ans
= countSubsetsRec(i + 1, j, k, N, K, D, a, dp);
if (j != K) {
ans = Math.Max(ans,
countSubsetsRec(i + 1, j + 1,
(k + a[i]) % D,
N, K, D, a, dp)
+ a[i]);
}
dp[i, j, k] = ans;
return ans;
}
public static void Main()
{
int N = 4, K = 2, D = 2;
int [] a = { 1, 2, 3, 4 };
if (countSubsets(N, K, D, a) < 0) {
Console.WriteLine( "-1" );
return ;
}
Console.WriteLine(countSubsets(N, K, D, a));
}
}
|
Javascript
function countSubsetsRec(i, j, k, N, K, D, a, dp) {
if (i === N) {
if (j === K && k === 0) {
return 0;
} else {
return Number.MIN_SAFE_INTEGER;
}
}
if (dp[i][j][k] !== -1) {
return dp[i][j][k];
}
let ans = countSubsetsRec(i + 1, j, k, N, K, D, a, dp);
if (j !== K) {
ans = Math.max(ans, countSubsetsRec(i + 1, j + 1, (k + a[i]) % D, N, K, D, a, dp) + a[i]);
}
dp[i][j][k] = ans;
return ans;
}
function countSubsets(N, K, D, a) {
const dp = new Array(N + 1).fill( null ).map(() =>
new Array(K + 1).fill( null ).map(() => new Array(D).fill(-1))
);
return countSubsetsRec(0, 0, 0, N, K, D, a, dp);
}
const N = 4, K = 2, D = 2;
const a = [1, 2, 3, 4];
if (countSubsets(N, K, D, a) < 0) {
console.log(-1);
}
console.log(countSubsets(N, K, D, a));
|
Time Complexity: O(NKD), since we are doing nested iteration N*K*D times.
Auxiliary Space: O(NKD), for creating the dp array.
Approach: To solve the problem using the Bottom-up Dp approach follow the below idea:
Let’s define dp[i][j][k] as the maximum sum of j elements chosen out of A[1], A[2], ….., A[i] such that the remainder when the sum is divided by D is k (or −1 if it is impossible).
Now there can be two cases:
- Skip the current elements, we can update the dp as:
- dp[i + 1][j][k] = max(dp[i + 1][j][k], dp[i][j][k])
- Take the current element, we can update the dp as:
- dp[i + 1][j + 1][(k + a[i]) % D] = max(dp[i + 1][j + 1][(k + a[i]) % D], dp[i][j][k] + a[i])
The final answer is stored in state dp[n][k][0].
Steps that were to follow the above approach:
- Initialize a dp array of (N+1)*(K+1)*(D) size with all states as -1, and dp[0][0][0] = 0.
- Now iterate for i in the range [0, N), for j in the range [0, K], and for k in the range [0, D).
- If dp[i][j][k] = -1, then this state is not reachable.
- Otherwise, we can do the transition as mentioned.
- For the second case where we have to choose the element, check if the number of chosen elements till now is not equal to K, i.e., j != K.
- Return the final answer as dp[n][k][0].
Below is the code to implement the above approach:
C++
#include <bits/stdc++.h>
using namespace std;
int countSubsets( int N, int K, int D, vector< int > a)
{
long long dp[N + 1][K + 1][D];
memset (dp, -1, sizeof (dp));
dp[0][0][0] = 0;
for ( int i = 0; i < N; i++) {
for ( int j = 0; j < K + 1; j++) {
for ( int k = 0; k < D; k++) {
if (dp[i][j][k] == -1)
continue ;
dp[i + 1][j][k]
= max(dp[i + 1][j][k], dp[i][j][k]);
if (j != K) {
dp[i + 1][j + 1][(k + a[i]) % D] = max(
dp[i + 1][j + 1][(k + a[i]) % D],
dp[i][j][k] + a[i]);
}
}
}
}
return dp[N][K][0];
}
int main()
{
int N = 4, K = 2, D = 2;
vector< int > a = { 1, 2, 3, 4 };
cout << countSubsets(N, K, D, a);
return 0;
}
|
Java
import java.util.Arrays;
import java.util.Vector;
public class Main {
static int countSubsets( int N, int K, int D, Vector<Integer> a) {
long [][][] dp = new long [N + 1 ][K + 1 ][D];
for ( long [][] layer1 : dp) {
for ( long [] layer2 : layer1) {
Arrays.fill(layer2, - 1 );
}
}
dp[ 0 ][ 0 ][ 0 ] = 0 ;
for ( int i = 0 ; i < N; i++) {
for ( int j = 0 ; j < K + 1 ; j++) {
for ( int k = 0 ; k < D; k++) {
if (dp[i][j][k] == - 1 )
continue ;
dp[i + 1 ][j][k] = Math.max(dp[i + 1 ][j][k], dp[i][j][k]);
if (j != K) {
dp[i + 1 ][j + 1 ][(k + a.get(i)) % D] = Math.max(
dp[i + 1 ][j + 1 ][(k + a.get(i)) % D],
dp[i][j][k] + a.get(i));
}
}
}
}
return ( int ) dp[N][K][ 0 ];
}
public static void main(String[] args) {
int N = 4 , K = 2 , D = 2 ;
Vector<Integer> a = new Vector<>(Arrays.asList( 1 , 2 , 3 , 4 ));
System.out.println(countSubsets(N, K, D, a));
}
}
|
Python3
def countSubsets(N, K, D, a):
dp = [[[ - 1 for _ in range (D)] for _ in range (K + 1 )] for _ in range (N + 1 )]
dp[ 0 ][ 0 ][ 0 ] = 0
for i in range (N):
for j in range (K + 1 ):
for k in range (D):
if dp[i][j][k] = = - 1 :
continue
dp[i + 1 ][j][k] = max (dp[i + 1 ][j][k], dp[i][j][k])
if j ! = K:
dp[i + 1 ][j + 1 ][(k + a[i]) % D] = max (dp[i + 1 ][j + 1 ]
[(k + a[i]) % D], dp[i][j][k] + a[i])
return dp[N][K][ 0 ]
N = 4
K = 2
D = 2
a = [ 1 , 2 , 3 , 4 ]
print (countSubsets(N, K, D, a))
|
C#
using System;
class Program
{
static int CountSubsets( int N, int K, int D, int [] a)
{
long [,,] dp = new long [N + 1, K + 1, D];
for ( int i = 0; i <= N; i++)
{
for ( int j = 0; j <= K; j++)
{
for ( int k = 0; k < D; k++)
{
dp[i, j, k] = -1;
}
}
}
dp[0, 0, 0] = 0;
for ( int i = 0; i < N; i++)
{
for ( int j = 0; j < K + 1; j++)
{
for ( int k = 0; k < D; k++)
{
if (dp[i, j, k] == -1)
continue ;
dp[i + 1, j, k]
= Math.Max(dp[i + 1, j, k], dp[i, j, k]);
if (j != K)
{
dp[i + 1, j + 1, (k + a[i]) % D] = Math.Max(
dp[i + 1, j + 1, (k + a[i]) % D],
dp[i, j, k] + a[i]);
}
}
}
}
return ( int )dp[N, K, 0];
}
static void Main( string [] args)
{
int N = 4, K = 2, D = 2;
int [] a = { 1, 2, 3, 4 };
Console.WriteLine(CountSubsets(N, K, D, a));
}
}
|
Javascript
function countSubsets(N, K, D, a) {
let dp = new Array(N + 1);
for (let i = 0; i <= N; i++) {
dp[i] = new Array(K + 1);
for (let j = 0; j <= K; j++) {
dp[i][j] = new Array(D);
for (let k = 0; k < D; k++) {
dp[i][j][k] = -1;
}
}
}
dp[0][0][0] = 0;
for (let i = 0; i < N; i++) {
for (let j = 0; j <= K; j++) {
for (let k = 0; k < D; k++) {
if (dp[i][j][k] === -1) {
continue ;
}
dp[i + 1][j][k] = Math.max(dp[i + 1][j][k], dp[i][j][k]);
if (j !== K) {
dp[i + 1][j + 1][(k + a[i]) % D] = Math.max(
dp[i + 1][j + 1][(k + a[i]) % D],
dp[i][j][k] + a[i]
);
}
}
}
}
return dp[N][K][0];
}
let N = 4;
let K = 2;
let D = 2;
let a = [1, 2, 3, 4];
console.log(countSubsets(N, K, D, a));
|
Time Complexity: O(N*K*D), since we are doing nested iteration N*K*D times.
Auxiliary Space: O(N*K*D), for creating the dp array.
Related Articles:
Share your thoughts in the comments
Please Login to comment...