I am looking for an algorithm to identify combinations of game outcomes that maximize total points. The rules for the combinations
are as follows:
There are a total of N games
Each game has 3 possible outcomes (win, lose, or draw)
Each outcome has positive or negative score
Find the top outcome combinations of size N in order to maximize the total score
For example, with N = 2:
Game 1, Outcome 1 = +3 points
Game 1, Outcome 2 = -1 points
Game 1, Outcome 3 = -3 points
Game 2, Outcome 1 = -3 points
Game 2, Outcome 2 = +1 points
Game 2, Outcome 3 = +3 points
With these 2 games and point values for each possible outcome, here is the ordered list of combinations I would expect to see. Note that combinations 4, 5, and 6 are ties so they could have been in any order here.
Combination 1 = (Game 1, Outcome 1) + (Game 2, Outcome 3) -> Total +6 points
Combination 2 = (Game 1, Outcome 1) + (Game 2, Outcome 2) -> Total +4 points
Combination 3 = (Game 1, Outcome 2) + (Game 2, Outcome 3) -> Total +2 points
Combination 4 = (Game 1, Outcome 1) + (Game 2, Outcome 1) -> Total 0 points
Combination 5 = (Game 1, Outcome 2) + (Game 2, Outcome 2) -> Total 0 points
Combination 6 = (Game 1, Outcome 3) + (Game 2, Outcome 3) -> Total 0 points
Combination 7 = (Game 1, Outcome 3) + (Game 2, Outcome 2) -> Total -2 points
Combination 8 = (Game 1, Outcome 2) + (Game 2, Outcome 1) -> Total -4 points
Combination 9 = (Game 1, Outcome 3) + (Game 2, Outcome 1) -> Total -6 points
I can compute these ordered combinations by brute force for small values of N, but given that there are a total of 3^N combinations and that N can be as large as 128, I don't expect brute force to work for very long. So, I am looking for a way to identify the first M combinations, where M << the total number (3^N) of combinations.
I've spent quite a bit of time trying to come up with an algorithmic way to pick these combinations but I'm coming up short. I'd appreciate any suggestions that point me in the right direction.
Thanks
You can generate M combinations iteratively using a Priority Queue. First, you need to make a data structure that represents a single combination, along with a function to compute its score. For example, you could use an array of N small integers representing the number of the outcome. Use the score function to order the combinations inside the queue.
You will also need a way to quickly identify that you have seen a particular combination. For that your combination representation needs to have a hash function. Make a hash set of the combinations that you have explored.
It is trivial to compute the top combination: you can do it by grabbing the highest-value outcome for each of the N games. Add this combination to the priority queue, then run the following loop:
Dequeue the next best combination, and add it to the list of results.
If the length of the result list is M, you are done
Otherwise, go through the current combination, and produce up to 2N "derived" combinations from it
Each derived combination differs from the current combination in a single game outcome
Flip the outcome of each game from the best to the second best, then to the worst.
Check the combination with "flipped" outcomes against the hash set of the combinations you have explored
If this is a new combination, add it to the hash set and also to the priority queue
When you are done with the derived combinations, trim the queue down to M-res items, where res is the number of items on the results list
Continue to the next iteration.
Related
I'm going through the Daily Coding Problems and am currently stuck in one of the problems. It goes by:
You are given an array of length N, where each element i represents
the number of ways we can produce i units of change. For example, [1,
0, 1, 1, 2] would indicate that there is only one way to make 0, 2, or
3 units, and two ways of making 4 units.
Given such an array, determine the denominations that must be in use.
In the case above, for example, there must be coins with values 2, 3,
and 4.
I'm unable to figure out how to determine the denomination from the total number of ways array. Can you work it out?
Somebody already worked out this problem here, but it's devoid of any explanation.
From what I could gather is that he collects all the elements whose value(number of ways == 1) and appends it to his answer, but I think it doesn't consider the fact that the same number can be formed from a combination of lower denominations for which still the number of ways would come out to be 1 irrespective of the denomination's presence.
For example, in the case of arr = [1, 1, a, b, c, 1]. We know that denomination 1 exists since arr[1] = 1. Now we can also see that arr[5] = 1, this should not necessarily mean that denomination 5 is available since 5 can be formed using coins of denomination 1, i.e. (1 + 1 + 1 + 1 + 1).
Thanks in advance!
If you're solving the coin change problem, the best technique is to maintain an array of ways of making change with a partial set of the available denominations, and add in a new denomination d by updating the array like this:
for i = d upto N
a[i] += a[i-d]
Your actual problem is the reverse of this: finding denominations based on the total number of ways. Note that if you know one d, you can remove it from the ways array by reversing the above procedure:
for i = N downto d
a[i] -= a[i-d]
You can find the lowest denomination available by looking for the first 1 in the array (other than the value at index 0, which is always 1). Then, once you've found the lowest denomination, you can remove its effect on the ways array, and repeat until the array is zeroed (except for the first value).
Here's a full solution in Python:
def rways(A):
dens = []
for i in range(1, len(A)):
if not A[i]: continue
dens.append(i)
for j in range(len(A)-1, i-1, -1):
A[j] -= A[j-i]
return dens
print(rways([1, 0, 1, 1, 2]))
You might want to add error-checking: if you find a non-zero value that's not 1 when searching for the next denomination, then the original array isn't valid.
For reference and comparison, here's some code for computing the ways of making change from a set of denominations:
def ways(dens, N):
A = [1] + [0] * N
for d in dens:
for i in range(d, N+1):
A[i] += A[i-d]
return A
print(ways([2, 3, 4], 4))
Consider the following game:
You have a tower of N cubes. Each turn, the player can take from the tower only prime number, or power of prime number of cubes.
The winner it the last player who plays, meaning the last player to take prime number (or power of prime number) of cubes and there are no more cubes left.
Notes:
1) The run time for each turn need to be minimal.
2) There is no limit for numbers of turns
The goal:
a) Find an algorithm to win the game and also to determine if we need to be the first player or the second player, when there is only one tower.
b) same as a, but now we have 2 towers with different number of cubes.
Example:
if we have the number N=6, if we play first:
we can take 1, but player-2 will take 5 and win
we can take 2, but player-2 will take 4 and win (2 is prime number and power of 2)
we can take 3, but player-2 will take 3 and win
we can take 4, but player-2 will take 2 and win
we can take 5, but player-2 will take 1 and win
Therefor in this case the algorithm should determine that we must play second, and in this specific case we can choose to drop any amount of cubes we want.
The multiple pile version is a finite additive game, in that each tower is a separate game, people can choose which one to play in next, and the games are guaranteed to terminate in a finite number of steps with a clear victor. All additive games can be reduced to Nim.
Specifically the nim score of losing immediately is 0, winning immediately is 1, and otherwise a single tower of size n has the smallest possible nim score that you can't reach in one move, where possible nim scores are drawn from 0, 1, 2, ....
This allows us to recursively calculate nim scores for a single tower. The winning strategy will be to try to always give the other person a score of 0, and eventually you will make them lose. Note that if you're given a position with a nim score that is greater than 0, you can always find a move that gives the other person a score of 0 (if there was no way to get 0, then your nim score would have been 0). So if you've been given a position with a score of 0 and the other person plays correctly, you will always get a score of 0 and eventually we lose.
Now here is the basic result about additive games. If you can calculate nim scores for each of multiple towers, the nim score of the combination is just the xor of the individual nim scores.
So here are the first few nim scores.
0: 0 (you just lost)
1: 1 (nim(1-1) = 0)
2: 2 (nim(2-2) = 0, nim(2-1) = 1)
3: 3 (nim(3-3) = 0, nim(3-2) = 1, nim(3-1) = 2)
4: 4 (nim(4-4) = 0, nim(4-3) = 1, nim(4-2) = 2, nim(4-1) = 3)
5: 5 (nim(5-5) = 0, nim(5-4) = 1, nim(5-3) = 2, nim(5-2) = 3, nim(5-1) = 4)
6: 0 (can't get 0)
7: 1 (nim(7-7) = 0)
8: 2 (nim(8-8) = 0, nim(8-7) = 1)
9: 3 (nim(9-9) = 0, nim(9-8) = 1, nim(9-7) = 2)
10: 4 (nim(10 - 4) = 0, nim(10-9) = 2, nim(10-8) = 2, nim(10-7) = 3)
And so on. It is easy to calculate this recursively. Memoize, and it will be O(n**2 / log(n)) (For each of n numbers, construct the set of nim values that you could reach after all O(n / log(n)) possible moves, then start counting from 0 up until after no more than O(n / log(n)) possible values you've found the first that is not achievable.)
To actually play it, you should store not only the nim score of the tower, but a lookup for how to get all of the better nim values that can be achieved from it. In a single tower version, that lets you immediately know how to play. In the multi-tower version it is slightly more complicated. When you're handed a position that has a non-zero nim score you should look for a tower whose nim score has a 1 in the leading binary digit of the score. You want to move with that tower to make its new nim score be the xor of the other towers. This new score will always be smaller than its current nim score, and therefore you will be able to make the move and hand back a 0 score.
I found an alternative solution-
You need always keep the number in the tower to be modulo 6 equal 0 so the rival can't take prime number (or power of prime number) of cubes.
For 2 towers, you need that both of the towers will be equally modulo, means that they both modulo 6 need to be the same.
I came across this problem where we need to find the total number of ways in which you can form a subset of n(where n is the input by the user). The subset conditions are : the numbers in the subset should be distinct and the numbers in the subset should be in decreasing order.
Example: Given n =7 ,the output is 4 because the possible combinations are (6,1)(5,2)(4,3)(4,2,1). Note that though (4,1,1,1) also add upto 7,however it has repeating numbers. Hence it is not a valid subset.
I have solved this problem using the backtracking method which has exponential complexity. However, I am trying to figure out how can we solve this problem using Dynamic Prog ? The nearest I could come up with is the series : for n= 0,1,2,3,4,5,6,7,8,9,10 for which the output is 0,0,0,1,1,2,3,4,5,7,9 respectively. However, I am not able to come up with a general formula that I can use to calculate f(n) . While going through the internet I came across this kind of integer sequences in https://oeis.org/search?q=0%2C0%2C0%2C1%2C1%2C2%2C3%2C4%2C5%2C7%2C9%2C11%2C14&sort=&language=&go=Search . But I am unable to understand the formula they have provided here. Any help would be appreciated. Any other insights that improves exponential complexity is also appreciated.
What you call "unique subset generation" is better known as integer partitions with distinct parts. Mathworld has an entry on the Q function, which counts the number of partitions with distinct parts.
However, your function does not count trivial partitions (i.e. n -> (n)), so what you're looking for is actually Q(n) - 1, which generates the sequence that you linked in your question--the number of partitions into at least 2 distinct parts. This answer to a similar question on Mathematics contains an efficient algorithm in Java for computing the sequence up to n = 200, which easily can be adapted for larger values.
Here's a combinatorial explanation of the referenced algorithm:
Let's start with a table of all the subsets of {1, 2, 3}, grouped by their sums:
index (sum) partitions count
0 () 1
1 (1) 1
2 (2) 1
3 (1+2), (3) 2
4 (1+3) 1
5 (2+3) 1
6 (1+2+3) 1
Suppose we want to construct a new table of all of subsets of {1, 2, 3, 4}. Notice that every subset of {1, 2, 3} is also a subset of {1, 2, 3, 4}, so each subset above will appear in our new table. In fact, we can divide our new table into two equally sized categories: subsets which do not include 4, and those that do. What we can do is start from the table above, copy it over, and then "extend" it with 4. Here's the table for {1, 2, 3, 4}:
index (sum) partitions count
0 () 1
1 (1) 1
2 (2) 1
3 (1+2), (3) 2
4 (1+3), [4] 2
5 (2+3), [1+4] 2
6 (1+2+3),[2+4] 2
7 [1+2+4],[3+4] 2
8 [1+3+4] 1
9 [2+3+4] 1
10 [1+2+3+4] 1
All the subsets that include 4 are surrounded by square brackets, and they are formed by adding 4 to exactly one of the old subsets which are surrounded by parentheses. We can repeat this process and build the table for {1,2,..,5}, {1,2,..,6}, etc.
But we don't actually needed to store the actual subsets/partitions, we just need the counts for each index/sum. For example, if with have the table for {1, 2, 3} with only counts, we can build the count-table for {1, 2, 3, 4} by taking each (index, count) pair from the old table, and adding count to the the current count for index + 4. The idea is that, say, if there are two subsets of {1, 2, 3} that sum to 3, then adding 4 to each of those two subsets will make two new subsets for 7.
With this in mind, here's a Python implementation of this process:
def c(n):
counts = [1]
for k in range(1, n + 1):
new_counts = counts[:] + [0]*k
for index, count in enumerate(counts):
new_counts[index + k] += count
counts = new_counts
return counts
We start with the table for {}, which has just one subset--the empty set-- which sums to zero. Then we build the table for {1}, then for {1, 2}, ..., all the way up to {1,2,..,n}. Once we're done, we'll have counted every partition for n, since no partition of n can include integers larger than n.
Now, we can make 2 major optimizations to the code:
Limit the table to only include entries up to n, since that's all we're interested in. If index + k exceeds n, then we just ignore it. We can even preallocate space for the final table up front, rather than growing bigger tables on each iteration.
Instead of building a new table from scratch on each iteration, if we carefully iterate over the old table backwards, we can actually update it in-place without messing up any of the new values.
With these optimizations, you effectively have the same algorithm from the Mathematics answer that was referenced earlier, which was motivated by generating functions. It runs in O(n^2) time and takes only O(n) space. Here's what it looks like in Python:
def c(n):
counts = [1] + [0]*n
for k in range(1, n + 1):
for i in reversed(range(k, n + 1)):
counts[i] += counts[i - k]
return counts
def Q(n):
"-> the number of subsets of {1,..,n} that sum to n."
return c(n)[n]
def f(n):
"-> the number of subsets of {1,..,n} of size >= 2 that sum to n."
return Q(n) - 1
So to demonstrate what I'm hoping to achieve I'll use a deck of cards.
Let's say there are three people, each with their own randomly shuffled deck. The cards in the deck simply have values 1 through 13, and there are four of each card.
When it comes time to draw a card, everyone takes their top card and shows its value to the other two players.
What I want now, is some way to map the values of each of these top cards to a single integer from 1 - 13. The goal being that this algorithm would generate something unique for each operation, and only allow for 4 of the same value (when the exact same inputs are calculated each of 4 times it can happen).
I know I can use Cantor Pairing Function to generate a unique value, but again I want it to be in the range 1-13.
The Cantor pairing function is only necessary if you want to map all positive integers. What's wrong with simply the following, with n = 13 and N = n^4?
(val1 - 1) * n^3 + (val2 - 1) * n^2 + (val3 - 1) * n + (val4 - 1) + 1
The ordering can be given by the suit of the card, or the order in which they are drawn.
N transmitters are positioned on a straight road, their position and signal strength is given.
Transmitters can cover distance on either side of the road evenly, i.e. a transmitter with signal
strength of ādā can cover total ā2dā length. You need to find all regions which receive signals from
atleast K transmitters.
directi, medianet interview questions
x = [5, 8, 13, 16]
d = [2, 6, 1, 4]
(3,7), (2, 14), (12,14), (12, 20)
First,make two arrays for storing X and Y coordinates by doing x+d and x-d from your input array. One simple way is of O(n^2), find the intervals for each starting point.
Optimize way is to just create a interval tree and insert the intervals. Interval tree is a self balancing binary search tree, hence you can get the results in O(nlogn). Here is the link to Interval tree.
Make a list (array) of pairs (StartOfInterval, +1) and (EndOfInterval, -1) for all interval ends.
Sort this list by the first field
NumberTranmittersHere = 0
Walk through the list, adding the second field of pair to NumberTranmittersHere
Check if current value is at least K
(3+),(7-),(2+),(14-),(12+),(14-),(12+),(20-)
(2+),(3+),(7-),(12+),(12+),(14-),(14-),(20-)
NTH 0 1 2 1 2 3 2 1 0