Dynamic Programing to generate combinations - java

I had a technical phone interview and I was doing well until i was asked this question. I was totally lost i had very little idea on how to solve such a problem.
You are given the following inputs: Total Score, Number of Players, Scores by each player. Sample Input would be
10 4 3 5 5 7
Where
10 = Total Score
4 = 4 players
3 = Score by player 1
5 = Score by player 2
5 = Score by player 3
7 = Score by player 4
You are to print out any combination that equals the total score. For instance we know player 4 and player 1 can have combine score of total score 10. So output for the above answer would be
1 4
1 = INDEX of player 1 4 = INDEX of player 4. Yes i know index of player 1 is technically 0 but they said print it out as such. If no combination matched you can print out none or anything you like . That didn't matter.
MY ATTEMPT
Well rather than being silent i first told interviewer i can use brute force approach to solve this. He said of course but we need better run time.
So i started thinking we could find all the possible combinations that could lead the total dollar and use MEMOIZATION to store the previously stored values. I was not able to think of a way of generating all combos and so i got stuck there.
Update
He also mentioned the maximum score i can give you is 1000. I am not even sure why this matters?
I would appreciate if someone can stir me in right direction or even provide pseudo/working java sample of how to solve such a problem. I think this is a generic problem and i really wanna understand how to solve this problem

This is the subset sum problem, and assuming your scores are relatively small integers, it can be solved in pseudo-polynomial time using DP:
D(i,0) = 1
D(0,x) = 0 x > 0
D(i,x) = D(i-1, x) + D(i-1, x-arr[i])
The above recursion formulas will generate the matrix of size total_score X num_players. The number of possible combination is denoted in the bottom right entry of the matrix.
The idea is to mimic an exhaustive search, for each person you can either add it or not add it, and invoke the recurse to a smaller problem.
Pseudo code for DP solution:
Input:
let W be the total score
let arr be the array of players scores
let n be the size of arr
Pseudo Code:
declare 2d array D of size W+1 X n+1
//initialization of "borders":
for each i from 0 to n+1:
D[i][0] = 1
for each x from 1 to W+1
D[0][x] = 0
//the DP:
for each i from 1 to n+1:
for each x from 1 to W+1:
if arr[i] < x:
D[i][x] = D[i-1][x]
else:
D[i][x] = D[i-1][x] + D[i-1][x-arr[i]]
//by here you have the matrix D filled up
//the wanted value is D[n][W]
return D[n][W]

Related

How to invert digits in Kattis - Add 'Em Up?

This image describes the Add Em Up! question from Kattis I was about to solve. Give me some ideas that I could employ while doing it.
I am stuck at how to edit such that the 2 or 5 can be inverted in an integer form.
How can I change a number 1223 or 152 whereby I can replace 2 by 5 or 5 by 2 so it becomes 1523 or 1553 and 125 or 122?
The problem description on this one is unclear. It seems like it's asking you to rotate the cards as you would physically, which entails replacing 6s and 9s, but that replacement never seems to be tested. You can get away with simply reversing the digits in the numbers.
To make matters worse, there's no sample test case with a 3, 4 or 7, which have no sensible representation in flipped form. Intuitively, these flips should be disregarded, and that intuition turns out to be true in the Kattis test suite.
Another edge case is what to do about 10 or 2100. These reverse to 1 and 12 respectively and shouldn't be ignored.
I am stuck at how to edit such that the 2 or 5 can be inverted in an integer form.
After spinning a card physically, 2 stays 2 and 5 stays 5. Only 6 and 9 would change values on a flip, and Kattis doesn't test those at this time. 2 and 5 mirror each other horizontally, but that's not relevant here.
After clarifying the requirements, the problem pretty much boils down to two sum with a reversal tossed in on certain numbers:
Create an empty lookup table
For each number in the input:
If lookup.contains(targetSum - newInputValue), then you found a sum
Otherwise, if 3, 4 and 7 aren't present in the string, do the following:
Produce the "flipped" value of the number by either operating on the digits or reversing the number as a string
If lookup.contains(targetSum - newInputValueFlipped), then you found a sum
Add the flipped value to the lookup table
Add the new input value to the lookup table
An "obvious" optimization is to cache each completed flip in a lookup table but it's not necessary to pass the challenge.
You can convert that number into string first
String str = "" + 123
StringBuilder myName = new StringBuilder(str);
Build a if condition inside a for loop and check for the given num 2 or 5 then replace the given number.
myName.setCharAt(i, '5');

Recursive algorithm for Budgeted Itinerary

I'm trying to solve a recursive problem. However, failing to come up with a working solution. When working with recursive problems I usually start by making an iterative one then converting it, but in this case, I was not able to do so...
The input is a list of n items given by their unit prices from least to most expensive, and a budget value; all positive integers.
method(int unitPriceList[], int budget )
Unit Price List = [ 3 , 7 , 9 ]. Budget = 18
The output prints all possible saturated itineraries as a list of item quantities, one list per line, each followed by its total price on the same line. The term saturated means that it is within budget, but it will fail to be within budget if we add any more item to it.
Quantities = [ 0 , 0 , 2 ]. Total Price = 18.
Quantities = [ 1 , 2 , 0 ]. Total Price = 17.
Quantities = [ 0 , 1 , 1 ]. Total Price = 16.
...
The number of saturated itineraries = …
I would be really appreciative if you could point me in the right direction to solve this problem.
This would be a case of the "all combinations of coins" problem. Find a solution for that. To convert to your case, add a unit coin (Price == 1). Now, reject any solution that has as many unit coins as your cheapest price (3 in this case).
Restating, you're looking for a count of the ways you can make 18 cents with coin denominations of (1, 3, 7, 9) -- but you can't use more than two 1-cent coins. That would require trading in those coins for a higher denomination.
Does that get you moving?

Is the 0/1 knapsack algorithm a suitable candidate here?

I have three categories of input , each with a impact range.
Cat 1 : 20 - 16
Cat 2 : 15 - 5
Cat 3 : 4 -1
I have a file with say N randomly generated categories.
I am trying to take a sum of impact for all the 100 entries through a logic that looks something like this :
// calculate sum of impacts
getSum(){
Generate a random class with seed as current system execution time
for(as many entries in file){
switch(category)
case 1 : i = random input between 20 - 16
case 2 : i = random input between 15 - 5
case 3 : i = random input between 4 - 1
some default case here
sum = sum + i
}
return sum
}
.
.
// loop until you get a desired sum
while(true){
if(Call to getSum() returns value within a desired range){
display some statistics;
break;
}
}
However , i see that the program generally runs infinitely , as the random generation and subsequent summation is giving result beyond the desired range. So , to get things in range , I have to manually tune the max-min ranges for each execution.
Can someone suggest an algorithm that will automatically vary the max min ranges for each category , by learning the trend of obtained sum as the program is running , so as to quickly give a solution ?
Edit : i have just read about the 0/1 knapsack algorithm.. and it seems promising , but unsure if that is the algorithm for this case. Any help would be great.
A couple band-aids:
1) use a long int instead of a regular int t give you a longer range.
2) use an unsigned long, since all of your relevant numbers are positive (then be careful of underflow errors when you subtract.
A couple possible strategies:
1) (This contradicts your question, but it is how things are usually done.) Determine the static maximum for each category, and design to it, using long unsigned int if that is large enough, or some larger data structure as necessary.
2) (This is exactly what you are asking.) Use, and build if necessary, a data structure which expands when an overflow occurs.
Solution for strategy 2:
I will get back to you on this. :)

Coin Change - Finding maximum Number

I'm having a hard time figuring out how to explain this problem. I'm currently trying to create a program for extra credit in my programming class, but I don't even understand the math behind it.... So I would love if someone could help me out. Alright:
Say you have 1 cent coin and a 4 cent coin. And the total number of coins allowed is 4. The maximal coverage of the value is 11. The chart is below.
Value | 1 cent | 4 cent
1 | 1
2 | 2
3 | 3
4 | 4
5 | 1 | 1
6 | 2 | 1
7 | 3 | 1
8 | | 2
9 | 1 | 2
10 | 2 | 2
11 | Maximum
S0 that's an example. I need to make this for something that is a much larger number. But I would love if someone can help explain the math for me. Or what the equation is... It's driving me insane.
I was trying to implement a version of the knapsack algorithm, but it doesn't seem to be doing the trick. If anyone can help it would be much appreciated. I'm not sure if I'm able to do that or if I need to use the greedy algorithm for this solution. It's basically a twist on the greedy algorithm.
EDIT: changed to 11
Dynamic programming (DP) is the way to solve the problem. DP generally involves finding some basic property you can compute based on other values of that property -- a form of inductive reasoning.
In your case, the basic question you need to ask is: "can I make n cents using exactly k coins". That's a simple boolean yes/no; because you can reuse coins, you don't need to know how to make n cents with k coins, only whether it is possible. This implicitly defines a boolean matrix A[n][k], where A[n][k] = TRUE iff you can make n cents with k of the given sorts of coins.
Study the relationships between the various entries in this truth table. For example, if I can make 5 cents with 2 coins, then it follows I can make 6 and 9 cents each with 3 coins (why?); thus A[5][2] implies A[6][3] and A[9][3].
Good luck!
Note: I'm re-posting because the other answer was deleted while updating to provide more context.
This appears to be the original problem author and his Java source code solution, if you'd like to study it further.
However, here's the summary of how this algorithm works, using dynamic programming:
Assumptions:
Each value in T is constrained by Integer.MAX_VALUE
T is constrained by Integer.MAX_VALUE -1
Definitions:
D = {d1, d2, ..., dk}∀ d∈ℤ, ∀ w_d = 1
T = W = Total Weight of Knapsack = Total Coins Available for Use
How the algorithm works:
Ensures W > 0 and that by 1 ∈ D
Ensures constraints above are met
Create a dynamically-sized array MinCoins[0] = 0
Let n=1 and iterate by 1 as n→∞
For each iteration, set MinCoins[ n ] = Integer.MAX_VALUE
Iterate over each element in D, let each value be known as d during iteration
If d > n skip this iteration
Let z represent the optimal number of coins for this iteration
Get the optimal number of coins from the previous iteration, and add one more (of this value) to it: z = MinCoins [ n - d ] + 1
Now compare z to MinCoins[ n ]
If z < MinCoins[ n ] a new optimal solution has been found (save it), else iterate to next d
Let the optimal solution found for this iteration be defined as q = MinCoins[ n ]
If q < T then continue to next iteration. Else, no maximum solution was found this iteration and break the loop.
https://bitbucket.org/asraful/coin-change

java random number generator - lottery

My code will seem amateurish as I am a software engineering student in 2nd year.
I created a lottery number generator and have noticed peculiar but consistent results. My program attempts to match the previous lottery numbers for the Euro Millions draw. I track the number of attempts it takes and i also track the number of times I match 3, 4, 5 and 6 numbers.
The attempts range between 1 million and 422 million. i.e. I would run the program 10 times and I would achieve a range, I would also track the length of time each run takes.
I account for a number of things like preventing a random number from being used more than once and this check is done against a HashMap of the possible lottery numbers. If I find the random number within the hashmap I add the number to an arraylist and then remove the number from the hashmap.
My questions surrounds the results.
In all attempts to match the lottery numbers my chance of getting 3 numbers was 3.13% on average. For 4 numbers it dropped to 0.28%, 5 numbers 0.00012% and 6 numbers 0.00022%.
Understandably The chance of winning as the number of lottery numbers increase is going to decrease however whether I had 1 million or 100 million attempts the ratio was the same or extremely close.
If you are interested my smallest number of attempts was 1,088,157, it took approximately 6 seconds or 6612ms.
Largest number of attempts was 422,036,905 and it took 26mins or 1589867ms.
Since I am using the Java Random library I am merely looking for some clarity on this. Or should I simply put it down to probability?
My code is an unnecessary 225 lines, if you would like to see a particular part or prefer to see the whole thing then please request this. Here is a sample below of the random number generation for the first 5 numbers.
//stores all possible lottery numbers
public static HashMap<Integer,Integer> randRange = new HashMap<Integer,Integer>();
//stores bonus ball numbers
public static HashMap<Integer,Integer> boRange = new HashMap<Integer,Integer>();
//stores lottery number output
public static ArrayList<Integer> lotNum = new ArrayList<Integer>();
//stores bonus ball output
public static ArrayList<Integer> boNum = new ArrayList<Integer>();
public static void randomInt(){
Random rand = new Random();
//generate a random number
int RandInt = rand.nextInt(51);
int boInt = rand.nextInt(12);
//loop used to get unique random number
int count=0;
while(count!=5){
//check if random number exists
if(randRange.get(RandInt)!=null)
{
//finalise random number
RandInt=randRange.get(RandInt);
//add to ArrayList
lotNum.add(RandInt);
//remove number
//ensures next random number is unique
randRange.remove(RandInt);
count++;
}
else
{
//get a new random number
//and start process again
RandInt = rand.nextInt(51);
}
}
}
EDIT:
First of all sorry I couldn't upvote as I have less than 15 reputation. All answers were helpful including comments.
Thanks to the suggestions by all members I improved my program and discovered unsurprisingly a fault in my code. #digitaljoel you were correct in the probability of matching 5 and 6 numbers. I set up the calculation incorrectly, e.g. for the numbers 11,20 30,35,45,2,3 for the euromillions draw to match 3 was 0.7%, 4 was .05%, 5 was .00273% and 6 was .000076%.
Thanks to #maybewecouldstealavan I changed my shuffling method to simply populate an ArrayList and shuffle the list, get the first five numbers and do the same for the bonus balls. The benefit was in the number of checks per second increasing from 150 - 200 thousand checks per second to 250-700 thousand checks per second.
Thanks to #trutheality as in some cases if i checked 1000 or 1,000,000 matches the variation was similar or minute.
#LeviX Appreciate again the calculation for the possible combinations. I used this within the program and found that it took more than the total number of combinations to win the lottery. Most likely I am producing duplicate random numbers. From this i will probably create all possible combinations and randomly select each combination until the program finds a match.
In all attempts to match the lottery numbers my chance of getting 3 numbers was 3.13% on average. For 4 numbers it dropped to 0.28%, 5 numbers 0.00012% and 6 numbers 0.00022%.
Understandably The chance of winning as the number of lottery numbers increase is going to decrease however whether I had 1 million or 100 million attempts the ratio was the same or extremely close.
That is actually not surprising at all. What you end up doing here is estimating the probability of guessing 3,4,5, or 6 numbers correctly. Having more samples will only make the variations in your estimates smaller, but even with "as little" as 1 million samples, your estimate is expected to be close to the exact probability (which you could calculate by doing some math).
Do you mean that you expect the proportion of times that you win to be more "random"? If that's what you're getting at, then #truthreality is quite correct. For further reading you might look at the law of large numbers and the central limit theorem.
If you're asking if your method of shuffling is correct, it is though it is inefficient. You're generating more random numbers than necessary, since you're just checking for dupes when they occur, and you're not creating a new random number after you pick a ball, so you're requiring a minimum of one HashMap.get(int) per pick.
I might use one of the following methods instead:
1) Create an ArrayList containing all the ball values. For each drawing, use Collections.shuffle(yourArrList, rand) to shuffle a clone of it them, then just use the first 5 balls from the list.
2) Again, create an Array or ArrayList of ball values. Then implement a portion of the shuffle operation yourself: Choose from smaller and smaller subsets of the possibilities and swap in the element that no longer fits into the place of the element that was just chosen. The advantage is that you don't need to shuffle the entire array. Here's my quick and dirty implementation:
public static int[] choose(int[] array, int count, Random rand) {
int[] ar = array.clone();
int[] out = new int[count];
int max = ar.length;
for (int i = 0; i<count; i++) {
int r = rand.nextInt(max);
//max is decremented,
//the selected value is copied out then overwritten
//by the last value, which would no longer be accessible
max--;
out[i]=ar[r];
ar[r]=ar[max];
}
return out;
}
There's probably room for improvement, especially if order doesn't matter.
From my understanding there are two different parts to the Euro Millions. The 5 balls and then the 2 bonus balls. You can check the math of your program by figuring out the exact probabilities of winning. I'm sure you can google it, but it's easy to calculate.
Probability of getting 5 balls out of 50 (order doesn't matter)
P(A) = 50!/5!(50-5)! = 2,118,760
Probability of getting 2 balls out of 11 (order doesn't matter)
P(B) 11!/2!(11-2)! = 55
The two events are independent so multiply them together.
P(A) * P(B) = P(A&B)
2,118,760 * 55 = 116,531,800
Therefore the chances of winning the lottery is:
1 in 116,531,800

Categories

Resources