Boredom
Gary is bored and wants to play an interesting but tough game. So he figured out a new board game called "destroy the neighbours". In this game, there are N integers on a board. In one move, he can pick any integer x from the board, and then all the integers with value x + 1 or x - 1 get destroyed. This move will give him x points.
He plays the game until the board becomes empty. But as he wants to show this game to his friend Steven, he wants to learn techniques to maximize the points to show off. Can you help Gary in finding out the maximum points he receives from the game?
Input Format:
The first line of input contains an integer ‘T’, denoting the number of test cases. Then each test case follows.
The first line of each test case contains the Integer ‘N’ denoting the number of elements in the array.
The second and the last line of each test case contains ‘N’ single space-separated integers representing the elements of the array.
Output Format:
For each test case, print a single integer ‘X’, denoting the maximum points he receives from the game.
Output of each test case will be printed on a separate line.
Note:
You do not need to print anything, it has already been taken care of. Just implement the given function.
Constraints:
1 <= T <= 5
1 <= N <= 10 ^ 5
1 <= arr[i] <= 10 ^ 6
Time Limit: 1 sec.
The idea is to store the frequency of each number from 0 to maximum element M.
Now for each element from 0 to M, there are two choices: either we pick it or skip it.
So, we can break the problem into subproblems using the following observation:
- If we pick element ‘x’, we must skip ‘x’ + 1.
- If we don’t pick ‘x’ then we may pick ‘x’ + 1 or skip it.
Let P(i, d) be the maximum point we can collect by picking elements from ‘i’ to M where 0 <= d <=1, if d is 0 it means we have picked the previous( i - 1 th) element else not.
Then,
P(i, 0) = max( P(i + 1, 1) + frequency[i] * i, P(i + 1, 0))
P(i, 1) = P(i + 1, 0)
This gives the optimal substructure.
Algorithm :
The steps are as follows:
- Run a loop from 0 to ‘n’ and store the maximum element in the variable ‘M’.
- Take a frequency array ‘frequency’ and store the initial frequency of all elements from 1 to ‘M’ to 0.
- Run a loop from 0 to 'n'.
- Update the frequency of each number Frequency[ arr[i] ]++.
- Make a helper function ‘helper(frequency, idx, M, d).
- Take a variable ‘ans’ and store the maximum of helper(frequency, 0, M, 0) and helper(frequency, 0, M, 1).
- Return ‘ans’.
Description of helper(frequency, idx, 1001, d) function
- If 'idx' is equal to 'n' return 0.
- Take a variable 'ans'
- If 'd' is equal to 0, it means previous element was not picked
- Store the maximum of when we pick element at 'idx' and if we don't pick it and store in ‘ans’ i.e ‘ans’ = max(helper(frequency, idx + 1, n, 1) + frequency[idx] * idx, helper(frequency, idx + 1, n, 0)).
- Else previous element was picked
- Skip this element and recursively call the ‘helper’ function on the next index i.e ‘ans’ = helper(frequency, idx + 1, n, 0).
The idea is to store the frequency of each number from 0 to maximum element range M.
Now for each element from 0 to M, there are two choices: either we pick it or skip it.
So, we can break the problem into subproblems using following observation:
- If we pick element ‘x’, we must skip ‘x’ + 1.
- If we don’t pick ‘x’ then we may pick ‘x’ + 1 or skip it.
Let P(i, d) be the maximum point we can collect by picking elements from ‘i’ to M, where 0 <= d <=1, if d is 0 it means we have picked the previous( i - 1 th) element else not.
Then,
P(i, 0) = max( P(i + 1, 1) + frequency[i] * i, P(i + 1, 0))
P(i, 1) = P(i + 1, 0)
This gives the optimal substructure.
If you observe, there are repetitive subproblems. We can avoid the recomputation of those repetitive subproblems by memoization.
Algorithm :
The steps are as follows:
- Run a loop from 0 to ‘n’ and store the maximum element in the variable ‘M’.
- Take a frequency array ‘frequency’ and store the initial frequency of all elements from 1 to ‘M’ to 0.
- Run a loop from 0 to 'n'.
- Update the frequency of each number Frequency[ arr[i] ]++.
- Take a 2D array of size 2 * M, let's say ‘dp’ and initialize it with -1.
- Make a helper function ‘helper(frequency, idx, M, d, dp).
- Take a variable ‘ans’ and store the maximum of helper(frequency, 0, M, 0) and helper(frequency, 0, M, 1).
- Return the final answer ‘ans’.
Description of helper(frequency, idx, M, d) function
- If 'idx' is equal to 'n' return 0.
- If dp[d][idx] is not equal to -1
- Return ‘dp[d][idx]’.
- Take the variable 'ans'.
- If 'd' is equal to 0, it means previous element was not picked:
- Store the maximum of when we pick element at 'idx' and if we don't pick it and store in ‘ans’ i.e ‘ans’ = max(helper(frequency, idx + 1, n, 1) + frequency[idx] * idx, helper(frequency, idx + 1, n, 0)).
- Else previous element was picked:
- Skip this element and recursively call the ‘helper’ function on the next index i.e ‘ans’ = helper(frequency, idx + 1, n, 0).
- Update ‘dp’ i.e dp[d][idx] = ‘ans’.
- Return ‘ans’.
Before coming to this question, what if array elements contain all the numbers from 1 to ‘N’. like 1, 2, 3, 4, 5, 6. Then you can clearly say that , if I select ith element then i will not select ‘i’ - 1 th element and if I don’t select ith element then to maximize points we must select i -1 th element. So, for every element there are two states either it is selected or not. Now this problem can give the sense of using dp ..right?
Similarly we can generalize this for duplicate elements like 1, 1, 2, 3, 3, 4, 4, 5.
We can keep the frequency of each element. The elements which are not present in the array then their frequency is 0.
State :
- dp[i] , the maximum points till ith element.
Transition:
- if ith element is selected then points = dp[i - 2] + i * frequency[i].
- If ith element is not selected then dp[i] is equal to dp[i - 1]. The answer will be the maximum number of above two.
- So dp[i] = max(dp[i-1], dp[i-2] + i * frequency[i]);.
Algorithm :
The steps are as follows:
- Run a loop from 0 to ‘n’ and store the maximum element in the variable ‘M’.
- Take a frequency array ‘frequency’ and store the initial frequency of all elements from 1 to M i.e 0.
- Run a loop from 0 to 'n' and update the frequency of each number.
- Take a 'dp' array of length M it stores the maximum Points till 'i'.
- Initialize 'dp[0]' to 0 and dp[1] equal to frequency[1].
- Run a loop from 2 to 1000 and update the value of dp[i]
- dp[i] = max(dp[i-1], dp[i-2] + i * frequency[i]).
- Return dp[M].