Mathematical solution to split X teams into 3 Teams per day - algorithm

I am trying to split X number of Teams into "play days" which consist of 3 teams per day
There is more than one solution to solve this for 15 teams.
What is the best approach to find all possible fixtures/match plans for team count 9-21?
Team count of 11, 14, 17 and 20 also cause problems, because total_matches/3="must be even/integer"
15 Teams // 105 Total Matches // 35 Total Days
D1 = 1:2 1:3 2:3
D2 = 2:4 2:5 4:5
D3 = 3:4 3:6 4:6
D4 = 4:1 4:7 1:7
D5 = 5:1 5:6 1:6
D6 = 6:2 6:7 2:7
7 = 7:3 7:5 3:5
8 = 8:1 8:9 1:9
9 = 9:2 9:10 2:10
10 = 10:1 10:11 1:11
11 = 11:2 11:8 2:8
12 = 12:1 12:13 1:13
13 = 13:2 13:14 2:14
14 = 14:1 14:15 1:15
15 = 2:12 2:15 12:15
16 = 3:8 3:10 8:10
17 = 3:9 3:11 9:11
18 = 3:12 3:14 12:14
19 = 4:8 4:12 8:12
20 = 5:8 5:13 8:13
21 = 6:8 6:14 8:14
22 = 7:8 7:15 8:15
23 = 9:4 9:13 4:13
24 = 9:5 9:12 5:12
25 = 10:4 10:14 4:14
26 = 11:4 11:15 4:15
27 = 12:6 12:10 6:10
28 = 13:3 13:15 3:15
29 = 14:5 14:11 5:11
30 = 5:10 5:15 10:15
D31 = 6:9 6:15 9:15
D32 = 6:11 6:13 11:13
D33 = 7:9 7:14 9:14
D34 = 7:10 7:13 10:13
D35 = 7:11 7:12 11:12

(Python) The following chooses the next three teams to group per day based on those teams that have played the least games so far and gives an ideal solution for the 9 teams case:
from itertools import combinations
from string import ascii_uppercase
TEAMCOUNT = 9
teams = ascii_uppercase[:TEAMCOUNT] # Just use uppercase letters for teams
# All needed 2-team games
games = {''.join(two_teams) for two_teams in combinations(teams, 2)}
# All possible 3-team days and the 2-team matches they map to
triples = {x + y + z: {x+y, x+z, y+z}
for x, y, z in combinations(teams, 3) }
print('Teams:', teams)
n = 0
while games and triples:
# Weighting based on number of games left to play
weight = {t: sum(t in g for g in games) for t in teams}
to_play = {t1+t2: min([weight[t1], weight[t2]]) for t1, t2 in games}
# Choose teams that haven't played much next
_, chosen_triple = max((sum(to_play[m] for m in matches if m in games),
day)
for day, matches in triples.items())
n += 1
print(f" Day{n}: {chosen_triple} Games: ",
' '.join(sorted(m for m in triples[chosen_triple] if m in games)))
games -= triples[chosen_triple] # These games are played
del triples[chosen_triple] # This day triple used
if games:
print(" After those days, the following games remain to be played:", ' '.join(sorted(games)))
else:
print(" All games played!")
Output for 9 Teams:
Teams: ABCDEFGHI
Day1: GHI Games: GH GI HI
Day2: DEF Games: DE DF EF
Day3: ABC Games: AB AC BC
Day4: CFI Games: CF CI FI
Day5: BEH Games: BE BH EH
Day6: ADG Games: AD AG DG
Day7: CEG Games: CE CG EG
Day8: BDI Games: BD BI DI
Day9: AFH Games: AF AH FH
Day10: CDH Games: CD CH DH
Day11: BFG Games: BF BG FG
Day12: AEI Games: AE AI EI
All games played!

The number of possible combinations/matches of teams can mathematically be described as a Triangular Number.
For example, when there is 9 teams, the number of matches is 36.
Notice, that this number is only divisible by 3 when k or k-1 is divisible by 3. With 5 teams, you will end up with 10 possible games. Your last week will only have 1 game or you can structure it differently.
If you want to write out the combinations of matches, you can list them by iterating through the number of teams twice. Here is some example Java code. You may run it in an online Java compiler.
public class MyClass {
public static void main(String args[]) {
int TEAMS = 10; //Number of teams
int combos = 0;
for(int i = 1; i <= TEAMS-1; i++){
for(int j = i+1; j <= TEAMS; j++){
System.out.println("Team " + i + " plays Team " + j);
combos ++;
}
}
System.out.println("There is " + combos + " possible matches");
}
}
We don't just want every combination of 2 teams. We want to look at combinations of 3 teams. Mathematically, we want a Combination.
We can rewrite our Triangular number as n choose k. Our previous example becomes:
Every week that we choose has 3 teams playing. The total possible day combinations is n choose 3. In our example with 9 teams.
We have 84 possible day combinations. Many of these days have overlapping games. For example, if we have teams 1, 2, and 3 play one day, then we don't want another day with teams 1,2 and 4 because then 1 and 2 play 2 games against each other. The solution for this could be to ignore duplicated games.
I want to point out that a perfect solution does not exist. For most number of teams, there is not a solution where every day 3 teams can play together that haven't already played. For example, when we have 4 teams, our games are:
1-2, 1-3, 1-4, 2-3, 2-4, 3-4. If we took 3 of those teams the first day (1-2, 1-3, 2-3) then the second day we don't get a perfect combination (1-4, 2-4, 3-4).
No matter how you break it, you can sort for the best combinations but you will end up with many random games at the end.
I created code below to look at every possible day combination and print out days that are not duplicated.
public class MyClass {
public static void main(String args[]) {
int TEAMS = 9; //Number of teams
//Keep track of each game combination used
boolean gamesPlayed[][] = new boolean[TEAMS+1][TEAMS+1];
int day = 1;
for(int i = 1; i <= TEAMS-2; i++){
for(int j = i+1; j <= TEAMS-1; j++){
for(int k = TEAMS; k >= j+1; k--){
if(!gamesPlayed[i][j] && !gamesPlayed[i][k] && !gamesPlayed[j][k] )
{
System.out.println("Day "+ day++ + " Teams " + i + ", " + j + " & " + k + " Play");
gamesPlayed[i][j] = true;
gamesPlayed[i][k] = true;
gamesPlayed[j][k] = true;
}
}
}
}
System.out.println("\nLeftover games");
for(int i = 1; i <= TEAMS-1; i++){
for(int j = i+1; j <= TEAMS; j++){
if(! gamesPlayed[i][j])
System.out.println(" Team " + i + " plays Team " + j);
}
}
}
}

Related

Subset sum with maximum equal sums and without using all elements

You are given a set of integers and your task is the following: split them into 2 subsets with an equal sum in such way that these sums are maximal. You are allowed not to use all given integers, that's fine. If it's just impossible, report error somehow.
My approach is rather straightforward: at each step, we pick a single item, mark it as visited, update current sum and pick another item recursively. Finally, try skipping current element.
It works on simpler test cases, but it fails one:
T = 1
N = 25
Elements: 5 27 24 12 12 2 15 25 32 21 37 29 20 9 24 35 26 8 31 5 25 21 28 3 5
One can run it as follows:
1 25 5 27 24 12 12 2 15 25 32 21 37 29 20 9 24 35 26 8 31 5 25 21 28 3 5
I expect sum to be equal 239, but it the algorithm fails to find such solution.
I've ended up with the following code:
#include <iostream>
#include <unordered_set>
using namespace std;
unordered_set<uint64_t> visited;
const int max_N = 50;
int data[max_N];
int p1[max_N];
int p2[max_N];
int out1[max_N];
int out2[max_N];
int n1 = 0;
int n2 = 0;
int o1 = 0;
int o2 = 0;
int N = 0;
void max_sum(int16_t &sum_out, int16_t sum1 = 0, int16_t sum2 = 0, int idx = 0) {
if (idx < 0 || idx > N) return;
if (sum1 == sum2 && sum1 > sum_out) {
sum_out = sum1;
o1 = n1;
o2 = n2;
for(int i = 0; i < n1; ++i) {
out1[i] = p1[i];
}
for (int i = 0; i < n2; ++i) {
out2[i] = p2[i];
}
}
if (idx == N) return;
uint64_t key = (static_cast<uint64_t>(sum1) << 48) | (static_cast<uint64_t>(sum2) << 32) | idx;
if (visited.find(key) != visited.end()) return;
visited.insert(key);
p1[n1] = data[idx];
++n1;
max_sum(sum_out, sum1 + data[idx], sum2, idx + 1);
--n1;
p2[n2] = data[idx];
++n2;
max_sum(sum_out, sum1, sum2 + data[idx], idx + 1);
--n2;
max_sum(sum_out, sum1, sum2, idx + 1);
}
int main() {
int T = 0;
cin >> T;
for (int t = 1; t <= T; ++t) {
int16_t sum_out;
cin >> N;
for(int i = 0; i < N; ++i) {
cin >> data[i];
}
n1 = 0;
n2 = 0;
o1 = 0;
o2 = 0;
max_sum(sum_out);
int res = 0;
int res2 = 0;
for (int i = 0; i < o1; ++i) res += out1[i];
for (int i = 0; i < o2; ++i) res2 += out2[i];
if (res != res2) cerr << "ERROR: " << "res1 = " << res << "; res2 = " << res2 << '\n';
cout << "#" << t << " " << res << '\n';
visited.clear();
}
}
I have the following questions:
Could someone help me to troubleshoot the failing test? Are there any obvious problems?
How could I get rid of unordered_set for marking already visited sums? I prefer to use plain C.
Is there a better approach? Maybe using dynamic programming?
Another approach is consider all the numbers till [1,(2^N-2)].
Consider the position of each bit to position of each element .Iterate all numbers from [1,(2^N-2)] then check for each number .
If bit is set you can count that number in set1 else you can put that number in set2 , then check if sum of both sets are equals or not . Here you will get all possible sets , if you want just one once you find just break.
1) Could someone help me to troubleshoot the failing test? Are there any obvious problems?
The only issue I could see is that you have not set sum_out to 0.
When I tried running the program it seemed to work correctly for your test case.
2) How could I get rid of unordered_set for marking already visited sums? I prefer to use plain C.
See the answer to question 3
3) Is there a better approach? Maybe using dynamic programming?
You are currently keeping track of whether you have seen each choice of value for first subset, value for second subset, amount through array.
If instead you keep track of the difference between the values then the complexity significantly reduces.
In particular, you can use dynamic programming to store an array A[diff] that for each value of the difference either stores -1 (to indicate that the difference is not reachable), or the greatest value of subset1 when the difference between subset1 and subset2 is exactly equal to diff.
You can then iterate over the entries in the input and update the array based on either assigning each element to subset1/subset2/ or not at all. (Note you need to make a new copy of the array when computing this update.)
In this form there is no use of unordered_set because you can simply use a straight C array. There is also no difference between subset1 and subset2 so you can only keep positive differences.
Example Python Code
from collections import defaultdict
data=map(int,"5 27 24 12 12 2 15 25 32 21 37 29 20 9 24 35 26 8 31 5 25 21 28 3 5".split())
A=defaultdict(int) # Map from difference to best value of subset sum 1
A[0] = 0 # We start with a difference of 0
for a in data:
A2 = defaultdict(int)
def add(s1,s2):
if s1>s2:
s1,s2=s2,s1
d = s2-s1
if d in A2:
A2[d] = max( A2[d], s1 )
else:
A2[d] = s1
for diff,sum1 in A.items():
sum2 = sum1 + diff
add(sum1,sum2)
add(sum1+a,sum2)
add(sum1,sum2+a)
A = A2
print A[0]
This prints 239 as the answer.
For simplicity I haven't bothered with the optimization of using a linear array instead of the dictionary.
A very different approach would be to use a constraint or mixed integer solver. Here is a possible formulation.
Let
x(i,g) = 1 if value v(i) belongs to group g
0 otherwise
The optimization model can look like:
max s
s = sum(i, x(i,g)*v(i)) for all g
sum(g, x(i,g)) <= 1 for all i
For two groups we get:
---- 31 VARIABLE s.L = 239.000
---- 31 VARIABLE x.L
g1 g2
i1 1
i2 1
i3 1
i4 1
i5 1
i6 1
i7 1
i8 1
i9 1
i10 1
i11 1
i12 1
i13 1
i14 1
i15 1
i16 1
i17 1
i18 1
i19 1
i20 1
i21 1
i22 1
i23 1
i25 1
We can easily do more groups. E.g. with 9 groups:
---- 31 VARIABLE s.L = 52.000
---- 31 VARIABLE x.L
g1 g2 g3 g4 g5 g6 g7 g8 g9
i2 1
i3 1
i4 1
i5 1
i6 1
i7 1
i8 1
i9 1
i10 1
i11 1
i12 1
i13 1
i14 1
i15 1
i16 1
i17 1
i19 1
i20 1
i21 1
i22 1
i23 1
i24 1
i25 1
If there is no solution, the solver will select zero elements in each group with a sum s=0.

Algorithm to find optimal groups in 2D array

I have a deck of 24 cards - 8 red, 8 blue and 8 yellow cards.
red |1|2|3|4|5|6|7|8|
yellow |1|2|3|4|5|6|7|8|
blue |1|2|3|4|5|6|7|8|
I can take 3 of cards (same numbers, straight, straigh flush), whereas each of the type is scored differently.
My question is, how to calculate maximal possible score (find optimal groups) for a game in progress, where some cards are already missing.
for example:
red |1|2|3|4|5|6|7|8|
yellow |1|2|3| |5| |7|8|
blue |1|2| |4|5|6| |8|
The score for a three-of-a-kind is:
1-1-1 20
2-2-2 30
3-3-3 40
4-4-4 50
5-5-5 60
6-6-6 70
7-7-7 80
8-8-8 90
The score for a straight is:
1-2-3 10
2-3-4 20
3-4-5 30
4-5-6 40
5-6-7 50
6-7-8 60
The score for a straight flush is:
1-2-3 50
2-3-4 60
3-4-5 70
4-5-6 80
5-6-7 90
6-7-8 100
A solution which recursively tries every combination would go like this:
Start looking at combinations that have a red 8 as the highest card: three-of-a-kind r8-y8-b8, straight flush r6-r7-r8, and every possible straight *6-*7-r8. For each of these, remove the cards from the set, and recurse to check combinations with the yellow 8, then blue 8, then red 7, yellow 7, blue 7, red 6 ... until you've checked everything except the 2's and 1's; then add three-of-a-kind 2-2-2 and 1-1-1 if available. At each step, check which recursion returns the maximum score, and return this maximum.
Let's look at what happens in each of these steps. Say we're looking at combinations with red 8; we have available cards like:
red ...|6|7|8|
yellow ...|6| |8|
blue ...| |7|8|
First, use three-of-a-kind r8-y8-b8, if possible. Create a copy of the available cards, remove the 8's, and recurse straight to the 7's:
score = 90 + max_score(cards_copy, next = red 7)
(Trying the three-of-a-kind should only be done when the current card is red, to avoid duplicate solutions.)
Then, use straight flush r6-r7-r8, if possible. Create a copy of the available cards, remove r6, r7 and r8, and recurse to yellow 8:
score = 100 + max_score(cards_copy, next = yellow 8)
Then, use every possible non-flush straight containing red 8; in the example, those are r6-b7-r8, y6-r7-r8 and y6-b7-r8 (there could be up to nine). For each of these, create a copy of the available cards, remove the three cards and recurse to yellow 8:
score = 60 + max_score(cards_copy, next = yellow 8)
Then, finally, recurse without using red 8: create a copy of the available cards, remove red 8 and recurse to yellow 8:
score = max_score(cards_copy, next = yellow 8)
You then calculate which of these options has the greatest score (with the score returned by its recursion added), and return that maximum score.
A quick test in JavaScript shows that for a full set of 24 cards, the algorithm goes through 30 million recursions to find the maximum score 560, and becomes quite slow. However, as soon as 3 higher-value cards have been removed, the number of recursions falls below one million and it takes around 1 second, and with 6 higher-value cards removed, it falls below 20,000 and returns almost instantly.
For almost-complete sets, you could pre-compute the maximum scores, and only calculate the score once a certain number of cards have been removed. A lot of sets will be duplicates anyway; removing r6-r7-r8 will result in the same maximum score as removing y6-y7-y8; removing r6-y7-b8 is a duplicate of removing b6-y7-r8... So first you change the input to a canonical version, and then you look up the pre-computed score. E.g. using pre-computed scores for all sets with 3 or 6 cards removed would require storing 45,340 scores.
As a code example, here's the JavaScript code I tested the algorithm with:
function clone(array) { // copy 2-dimensional array
var copy = [];
array.forEach(function(item) {copy.push(item.slice())});
return copy;
}
function max_score(cards, suit, rank) {
suit = suit || 0; rank = rank || 7; // start at red 8
var max = 0;
if (rank < 2) { // try 3-of-a-kind for rank 1 and 2
if (cards[0][0] && cards[1][0] && cards[2][0]) max += 20;
if (cards[0][1] && cards[1][1] && cards[2][1]) max += 30;
return max;
}
var next_rank = suit == 2 ? rank - 1: rank;
var next_suit = (suit + 1) % 3;
max = max_score(clone(cards), next_suit, next_rank); // try skipping this card
if (! cards[suit][rank]) return max;
if (suit == 0 && cards[1][rank] && cards[2][rank]) { // try 3-of-a-kind
var score = rank * 10 + 20 + max_score(clone(cards), 0, rank - 1);
if (score > max) max = score;
}
for (var i = 0; i < 3; i++) { // try all possible straights
if (! cards[i][rank - 2]) continue;
for (var j = 0; j < 3; j++) {
if (! cards[j][rank - 1]) continue;
var copy = clone(cards);
copy[j][rank - 1] = 0; copy[i][rank - 2] = 0;
var score = rank * 10 - 10 + max_score(copy, next_suit, next_rank);
if (i == suit && j == suit) score += 40; // straight is straight flush
if (score > max) max = score;
}
}
return max;
}
document.write(max_score([[1,1,1,1,1,0,1,1], [1,1,1,1,1,1,1,0], [1,1,1,0,1,1,1,1]]));
An obvious way to speed up the algorithm is to use a 24-bit pattern instead of a 3x8 bit array to represent the cards; that way the array cloning is no longer necessary, and most of the code is turned into bit manipulation. In JavaScript, it's about 8 times faster:
function max_score(cards, suit, rank) {
suit = suit || 0; rank = rank || 7; // start at red 8
var max = 0;
if (rank < 2) { // try 3-of-a-kind for rank 1 and 2
if ((cards & 65793) == 65793) max += 20; // 65793 = rank 1 of all suits
if ((cards & 131586) == 131586) max += 30; // 131586 = rank 2 of all suits
return max;
}
var next_rank = suit == 2 ? rank - 1: rank;
var next_suit = (suit + 1) % 3;
var this_card = 1 << rank << suit * 8;
max = max_score(cards, next_suit, next_rank); // try skipping this card
if (! (cards & this_card)) return max;
if (suit == 0 && cards & this_card << 8 && cards & this_card << 16) { // try 3oaK
var score = rank * 10 + 20 + max_score(cards, 0, rank - 1);
if (score > max) max = score;
}
for (var i = 0; i < 3; i++) { // try all possible straights
var mid_card = 1 << rank - 1 << i * 8;
if (! (cards & mid_card)) continue;
for (var j = 0; j < 3; j++) {
var low_card = 1 << rank - 2 << j * 8;
if (! (cards & low_card)) continue;
var cards_copy = cards - mid_card - low_card;
var score = rank * 10 - 10 + max_score(cards_copy, next_suit, next_rank);
if (i == suit && j == suit) score += 40; // straight is straight flush
if (score > max) max = score;
}
}
return max;
}
document.write(max_score(parseInt("111101110111111111011111", 2)));
// B Y R
// 876543218765432187654321
The speed for almost-complete sets can be further improved by using the observation that if a straight flush for all three suits can be be made for the current rank, then this is always the best option. This reduces the number of recursions drastically, because nine cards can be skipped at once. This check should be added immediately after trying 3-of-a-kind for rank 1 and 2:
if (suit == 0) { // try straight flush for all suits
var flush3 = 460551 << rank - 2; // 460551 = rank 1, 2 and 3 of all suits
if ((cards & flush3) == flush3) {
max = rank * 30 + 90;
if (rank > 2) max += max_score(cards - flush3, 0, rank - 3);
return max;
}
}

how to get the moore neighbourhood using index of a vector

I have a matrix in Rcpp (C++ for R) which is stored in column order in memory. Ie, it looks like:
[,1] [,2] [,3] [,4] [,5]
[1,] 1 6 11 16 21
[2,] 2 7 12 17 22
[3,] 3 8 13 18 23
[4,] 4 9 14 19 24
[5,] 5 10 15 20 25
Now, I have a single for loop that runs from i = 1 to 25 (bear in mind, it is all zero based, but here I am just saying one for convenience).
For every element of the matrix, I want its Moore neighbourhood. This is easy for the elements that are not on the edge. So if our selected index is idx and the size of the square matrix is nrow then we have
leftmid = idx - nrow
lefttop = (idx - nrow) - 1
leftbot = (idx - nrow) + 1
rightmid = idx + nrow
righttop = (idx + nrow) - 1
rightbot = (idx + nrow) + 1
midtop = idx - 1
midbot = idx + 1
But i cant figure out how to deal with the edge cases. For example, if idx = 3, then i want the neighbours:
leftmid = 23
lefttop = 22
leftbot = 24
rightmid = 8
righttop = 7
rightbot = 9
midtop = 2
midbot = 4
It's a little bit more complicated at the corner cases as well. My goal here is to reduce time. I am currently running my program with a double for loop which works, but is slower than reasonable. I want to change it into a single for loop to improve performance.
Edit: I realized the left and right boundaries can be obtained by modulus. So 3 - 5 %% 25 = 23. But I still have the top and bottom edge cases.
It appears you're interested in "cyclic" boundary conditions, where the matrix has a toroidal topology, i.e. the top wraps around to the bottom and the right wraps around to the left.
It might be easier to iterate with four loops, one each over the row and column, and then one each over the row and column of the neighborhood. Something like this should work:
int mooreNeighbors[3][3];
int nRows = 5;
int nCols = 5;
// Loop over the rows and columns of the matrix
for (int i = 0; i < nRows; ++i) {
for (int j = 0; j < nCols; ++j) {
// Loop over the cyclic Moore neighborhood
for (int mnI = 0; mnI < 3; ++mnI) {
for (int mnJ = 0; mnJ < 3; ++mnJ) {
// Sub-matrix indices
int subI = (i - mnI - 1) % nRows;
int subJ = (j - mnJ - 1) % nCols;
// Index into column-dominant matrix
int idx = subI + subJ*nRows;
mooreNeighbors[mnI][mnJ] = matrix[idx];
}
}
}
}
I haven't tried compiling this, but it should be close to correct and clear enough to correct any mistakes. Think of it as pseudo-code.
Also, I'm preferring clarity over optimality. For example, you don't have to do everything in the inner-most loop.

How can I fairly choose an item from a list?

Let's say that I have a list of prizes:
PrizeA
PrizeB
PrizeC
And, for each of them, I want to draw a winner from a list of my attendees.
Give that my attendee list is as follows:
user1, user2, user3, user4, user5
What is an unbiased way to choose a user from that list?
Clearly, I will be using a cryptographically secure pseudo-random number generator, but how do I avoid a bias towards the front of the list? I assume I will not be using modulus?
EDIT
So, here is what I came up with:
class SecureRandom
{
private RNGCryptoServiceProvider rng = new RNGCryptoServiceProvider();
private ulong NextUlong()
{
byte[] data = new byte[8];
rng.GetBytes(data);
return BitConverter.ToUInt64(data, 0);
}
public int Next()
{
return (int)(NextUlong() % (ulong)int.MaxValue);
}
public int Next(int maxValue)
{
if (maxValue < 0)
{
throw new ArgumentOutOfRangeException("maxValue");
}
if (maxValue == 0)
{
return 0;
}
ulong chop = ulong.MaxValue - (ulong.MaxValue % (ulong)maxValue);
ulong rand;
do
{
rand = NextUlong();
} while (rand >= chop);
return (int)(rand % (ulong)maxValue);
}
}
BEWARE:
Next() Returns an int in the range [0, int.MaxValue]
Next(int.MaxValue) Returns an int in the range [0, int.MaxValue)
Pseudocode for special random number generator:
rng is random number generator produces uniform integers from [0, max)
compute m = max modulo length of attendee list
do {
draw a random number r from rng
} while(r >= max - m)
return r modulo length of attendee list
This eliminates the bias to the front part of the list. Then
put the attendees in some data structure indexable by integers
for every prize in the prize list
draw a random number r using above
compute index = r modulo length of attendee list
return the attendee at index
In C#:
public NextUnbiased(Random rg, int max) {
do {
int r = rg.Next();
} while(r >= Int32.MaxValue - (Int32.MaxValue % max));
return r % max;
}
public Attendee SelectWinner(IList<Attendee> attendees, Random rg) {
int winningAttendeeIndex = NextUnbiased(rg, attendees.Length)
return attendees[winningAttendeeIndex];
}
Then:
// attendees is list of attendees
// rg is Random
foreach(Prize prize in prizes) {
Attendee winner = SelectWinner(attendees, rg);
Console.WriteLine("Prize {0} won by {1}", prize.ToString(), winner.ToString());
}
Assuming a fairly distributed random number generator...
do {
i = rand();
} while (i >= RAND_MAX / 5 * 5);
i /= 5;
This gives each of 5 slots
[ 0 .. RAND_MAX / 5 )
[ RAND_MAX / 5 .. RAND_MAX / 5 * 2 )
[ RAND_MAX / 5 * 2 .. RAND_MAX / 5 * 3 )
[ RAND_MAX / 5 * 3 .. RAND_MAX / 5 * 4 )
[ RAND_MAX / 5 * 4 .. RAND_MAX / 5 * 5 )
and discards a roll which falls out of range.
You have already seem several perfectly good answers that depend on knowing the length of the list in advance.
To fairly select a single item from a list without needing to know the length of the list in the first place do this:
if (list.empty()) error_out_somehow
r=list.first() // r is a reference or pointer
s=list.first() // so is s
i = 2
while (r.next() is not NULL)
r=r.next()
if (random(i)==0) s=r // random() returns a uniformly
// drawn integer between 0 and i
i++
return s
(Useful if you list is stored as a linked list)
To distribute prizes in this scenario, just walk down the list of prizes selecting a random winner for each one. (If you want to prevent double winning you then remove the winner from the participant list.)
Why does it work?
You start with the first item at 1/1
On the next pass, you select the second item half the time (1/2), which means that the first item has probability 1 * (2-1)/2 = 1/2
on further iteration, you select the nth item with probability 1/n, and the chance for each previous item is reduced by a factor of (n-1)/n
which means that when you come to the end, the chance of having the mth item in the list (of n items) is
1/m * m/(m+1) * (m+1)/(m+2) * ... * (n-2)/(n-1) * (n-1)/n = 1/n
and is the same for every item.
If you are paying attention, you'll note that this means walking the whole list every time you want to select an item from the list, so this is not maximally efficient for (say) reordering the whole list (though it does that fairly).
I suppose one answer would be to assign each item a random value, and take the largest or smallest, drilling down as necessary.
I'm not sure if this is the most efficient, tho...
If you're using a good number generator, even with a modulus your bias will be miniscule. If, for instance, you're using a random number generator with 64 bits of entropy and five users, your bias toward the front of the array should be on the order of 3x10^-19 (my numbers may be off, by I don't think by much). That's an extra 3-in-10-quintillion likelihood of the first user winning compared to the later users. That should be good enough to be fair in anyone's book.
You can buy truly random bits from a provider, or use a mechanical device.
Here you will find Oleg Kiselyov's discussion of purely functional random shuffling.
A description of the linked content (quoted from the beginning of that article):
This article will give two pure functional programs that perfectly,
randomly and uniformly shuffle a sequence of arbitrary elements. We
prove that the algorithms are correct. The algorithms are implemented
in Haskell and can trivially be re-written into other (functional)
languages. We also discuss why a commonly used sort-based shuffle
algorithm falls short of perfect shuffling.
You could use that to shuffle your list and then pick the first item of the shuffled result (or maybe you'd prefer not to give two prizes two the same person -- then use n initial positions of the result, for n = number of prizes); or you could simplify the algorithm to just produce the first item; or you could take a look around that site, because I could have sworn there's an article on picking one random element from an arbitrary tree-like structure with uniform distribution, in a purely functional way, proof of correctness provided, but my search-fu is failing me and I can't seem to find it.
Without truly random bits, you will always have some bias. The number of ways to assign prizes to guests is much larger than any common PRNG's period for even a fairly low number of guests and prizes. As suggested by lpthnc, buy some truly random bits, or buy some random-bit-generating hardware.
As for the algorithm, just do a random shuffle of the guest list. Be careful, as naive shuffling algorithms do have a bias: http://en.wikipedia.org/wiki/Shuffling#Shuffling_algorithms
You can 100% reliably pick a random item from any arbitrary list with a single pass and without knowing how many items are in the list ahead of time.
Psuedo Code:
count = 0.0;
item_selected = none;
foreach item in list
count = count + 1.0;
chance = 1.0 / count;
if ( random( 1.0 ) <= chance ) then item_selected = item;
Test program comparing results of a single rand() % N vs iterating as above:
#include "stdafx.h"
#include <stdio.h>
#include <stdlib.h>
#include <memory.h>
static inline float frand01()
{
return (float)rand() / (float)RAND_MAX;
}
int _tmain(int argc, _TCHAR* argv[])
{
static const int NUM_ITEMS = 50;
int resultRand[NUM_ITEMS];
int resultIterate[NUM_ITEMS];
memset( resultRand, 0, NUM_ITEMS * sizeof(int) );
memset( resultIterate, 0, NUM_ITEMS * sizeof(int) );
for ( int i = 0; i < 100000; i++ )
{
int choiceRand = rand() % NUM_ITEMS;
int choiceIterate = 0;
float count = 0.0;
for ( int item = 0; item < NUM_ITEMS; item++ )
{
count = count + 1.0f;
float chance = 1.0f / count;
if ( frand01() <= chance )
{
choiceIterate = item;
}
}
resultRand[choiceRand]++;
resultIterate[choiceIterate]++;
}
printf("Results:\n");
for ( int i = 0; i < NUM_ITEMS; i++ )
{
printf( "%02d - %5d %5d\n", i, resultRand[i], resultIterate[i] );
}
return 0;
}
Output:
Results:
00 - 2037 2050
01 - 2038 2009
02 - 2094 1986
03 - 2007 1953
04 - 1990 2142
05 - 1867 1962
06 - 1941 1997
07 - 2023 1967
08 - 1998 2070
09 - 1930 1953
10 - 1972 1900
11 - 2013 1985
12 - 1982 2001
13 - 1955 2063
14 - 1952 2022
15 - 1955 1976
16 - 2000 2044
17 - 1976 1997
18 - 2117 1887
19 - 1978 2020
20 - 1886 1934
21 - 1982 2065
22 - 1978 1948
23 - 2039 1894
24 - 1946 2010
25 - 1983 1927
26 - 1965 1927
27 - 2052 1964
28 - 2026 2021
29 - 2090 1993
30 - 2039 2016
31 - 2030 2009
32 - 1970 2094
33 - 2036 2048
34 - 2020 2046
35 - 2010 1998
36 - 2104 2041
37 - 2115 2019
38 - 1959 1986
39 - 1998 2031
40 - 2041 1977
41 - 1937 2060
42 - 1946 2048
43 - 2014 1986
44 - 1979 2072
45 - 2060 2002
46 - 2046 1913
47 - 1995 1970
48 - 1959 2020
49 - 1970 1997

algorithm to sum up a list of numbers for all combinations

I have a list of numbers and I want to add up all the different combinations.
For example:
number as 1,4,7 and 13
the output would be:
1+4=5
1+7=8
1+13=14
4+7=11
4+13=17
7+13=20
1+4+7=12
1+4+13=18
1+7+13=21
4+7+13=24
1+4+7+13=25
Is there a formula to calculate this with different numbers?
A simple way to do this is to create a bit set with as much bits as there are numbers.
In your example 4.
Then count from 0001 to 1111 and sum each number that has a 1 on the set:
Numbers 1,4,7,13:
0001 = 13=13
0010 = 7=7
0011 = 7+13 = 20
1111 = 1+4+7+13 = 25
Here's how a simple recursive solution would look like, in Java:
public static void main(String[] args)
{
f(new int[] {1,4,7,13}, 0, 0, "{");
}
static void f(int[] numbers, int index, int sum, String output)
{
if (index == numbers.length)
{
System.out.println(output + " } = " + sum);
return;
}
// include numbers[index]
f(numbers, index + 1, sum + numbers[index], output + " " + numbers[index]);
// exclude numbers[index]
f(numbers, index + 1, sum, output);
}
Output:
{ 1 4 7 13 } = 25
{ 1 4 7 } = 12
{ 1 4 13 } = 18
{ 1 4 } = 5
{ 1 7 13 } = 21
{ 1 7 } = 8
{ 1 13 } = 14
{ 1 } = 1
{ 4 7 13 } = 24
{ 4 7 } = 11
{ 4 13 } = 17
{ 4 } = 4
{ 7 13 } = 20
{ 7 } = 7
{ 13 } = 13
{ } = 0
The best-known algorithm requires exponential time. If there were a polynomial-time algorithm, then you would solve the subset sum problem, and thus the P=NP problem.
The algorithm here is to create bitvector of length that is equal to the cardinality of your set of numbers. Fix an enumeration (n_i) of your set of numbers. Then, enumerate over all possible values of the bitvector. For each enumeration (e_i) of the bitvector, compute the sum of e_i * n_i.
The intuition here is that you are representing the subsets of your set of numbers by a bitvector and generating all possible subsets of the set of numbers. When bit e_i is equal to one, n_i is in the subset, otherwise it is not.
The fourth volume of Knuth's TAOCP provides algorithms for generating all possible values of the bitvector.
C#:
I was trying to find something more elegant - but this should do the trick for now...
//Set up our array of integers
int[] items = { 1, 3, 5, 7 };
//Figure out how many bitmasks we need...
//4 bits have a maximum value of 15, so we need 15 masks.
//Calculated as:
// (2 ^ ItemCount) - 1
int len = items.Length;
int calcs = (int)Math.Pow(2, len) - 1;
//Create our array of bitmasks... each item in the array
//represents a unique combination from our items array
string[] masks = Enumerable.Range(1, calcs).Select(i => Convert.ToString(i, 2).PadLeft(len, '0')).ToArray();
//Spit out the corresponding calculation for each bitmask
foreach (string m in masks)
{
//Get the items from our array that correspond to
//the on bits in our mask
int[] incl = items.Where((c, i) => m[i] == '1').ToArray();
//Write out our mask, calculation and resulting sum
Console.WriteLine(
"[{0}] {1}={2}",
m,
String.Join("+", incl.Select(c => c.ToString()).ToArray()),
incl.Sum()
);
}
Outputs as:
[0001] 7=7
[0010] 5=5
[0011] 5+7=12
[0100] 3=3
[0101] 3+7=10
[0110] 3+5=8
[0111] 3+5+7=15
[1000] 1=1
[1001] 1+7=8
[1010] 1+5=6
[1011] 1+5+7=13
[1100] 1+3=4
[1101] 1+3+7=11
[1110] 1+3+5=9
[1111] 1+3+5+7=16
Here is a simple recursive Ruby implementation:
a = [1, 4, 7, 13]
def add(current, ary, idx, sum)
(idx...ary.length).each do |i|
add(current + [ary[i]], ary, i+1, sum + ary[i])
end
puts "#{current.join('+')} = #{sum}" if current.size > 1
end
add([], a, 0, 0)
Which prints
1+4+7+13 = 25
1+4+7 = 12
1+4+13 = 18
1+4 = 5
1+7+13 = 21
1+7 = 8
1+13 = 14
4+7+13 = 24
4+7 = 11
4+13 = 17
7+13 = 20
If you do not need to print the array at each step, the code can be made even simpler and much faster because no additional arrays are created:
def add(ary, idx, sum)
(idx...ary.length).each do |i|
add(ary, i+1, sum + ary[i])
end
puts sum
end
add(a, 0, 0)
I dont think you can have it much simpler than that.
Mathematica solution:
{#, Total##}& /# Subsets[{1, 4, 7, 13}] //MatrixForm
Output:
{} 0
{1} 1
{4} 4
{7} 7
{13} 13
{1,4} 5
{1,7} 8
{1,13} 14
{4,7} 11
{4,13} 17
{7,13} 20
{1,4,7} 12
{1,4,13} 18
{1,7,13} 21
{4,7,13} 24
{1,4,7,13} 25
This Perl program seems to do what you want. It goes through the different ways to choose n items from k items. It's easy to calculate how many combinations there are, but getting the sums of each combination means you have to add them eventually. I had a similar question on Perlmonks when I was asking How can I calculate the right combination of postage stamps?.
The Math::Combinatorics module can also handle many other cases. Even if you don't want to use it, the documentation has a lot of pointers to other information about the problem. Other people might be able to suggest the appropriate library for the language you'd like to you.
#!/usr/bin/perl
use List::Util qw(sum);
use Math::Combinatorics;
my #n = qw(1 4 7 13);
foreach my $count ( 2 .. #n ) {
my $c = Math::Combinatorics->new(
count => $count, # number to choose
data => [#n],
);
print "combinations of $count from: [" . join(" ",#n) . "]\n";
while( my #combo = $c->next_combination ){
print join( ' ', #combo ), " = ", sum( #combo ) , "\n";
}
}
You can enumerate all subsets using a bitvector.
In a for loop, go from 0 to 2 to the Nth power minus 1 (or start with 1 if you don't care about the empty set).
On each iteration, determine which bits are set. The Nth bit represents the Nth element of the set. For each set bit, dereference the appropriate element of the set and add to an accumulated value.
ETA: Because the nature of this problem involves exponential complexity, there's a practical limit to size of the set you can enumerate on. If it turns out you don't need all subsets, you can look up "n choose k" for ways of enumerating subsets of k elements.
PHP: Here's a non-recursive implementation. I'm not saying this is the most efficient way to do it (this is indeed exponential 2^N - see JasonTrue's response and comments), but it works for a small set of elements. I just wanted to write something quick to obtain results. I based the algorithm off Toon's answer.
$set = array(3, 5, 8, 13, 19);
$additions = array();
for($i = 0; $i < pow(2, count($set)); $i++){
$sum = 0;
$addends = array();
for($j = count($set)-1; $j >= 0; $j--) {
if(pow(2, $j) & $i) {
$sum += $set[$j];
$addends[] = $set[$j];
}
}
$additions[] = array($sum, $addends);
}
sort($additions);
foreach($additions as $addition){
printf("%d\t%s\n", $addition[0], implode('+', $addition[1]));
}
Which will output:
0
3 3
5 5
8 8
8 5+3
11 8+3
13 13
13 8+5
16 13+3
16 8+5+3
18 13+5
19 19
21 13+8
21 13+5+3
22 19+3
24 19+5
24 13+8+3
26 13+8+5
27 19+8
27 19+5+3
29 13+8+5+3
30 19+8+3
32 19+13
32 19+8+5
35 19+13+3
35 19+8+5+3
37 19+13+5
40 19+13+8
40 19+13+5+3
43 19+13+8+3
45 19+13+8+5
48 19+13+8+5+3
For example, a case for this could be a set of resistance bands for working out. Say you get 5 bands each having different resistances represented in pounds and you can combine bands to sum up the total resistance. The bands resistances are 3, 5, 8, 13 and 19 pounds. This set gives you 32 (2^5) possible configurations, minus the zero. In this example, the algorithm returns the data sorted by ascending total resistance favoring efficient band configurations first, and for each configuration the bands are sorted by descending resistance.
This is not the code to generate the sums, but it generates the permutations. In your case:
1; 1,4; 1,7; 4,7; 1,4,7; ...
If I have a moment over the weekend, and if it's interesting, I can modify this to come up with the sums.
It's just a fun chunk of LINQ code from Igor Ostrovsky's blog titled "7 tricks to simplify your programs with LINQ" (http://igoro.com/archive/7-tricks-to-simplify-your-programs-with-linq/).
T[] arr = …;
var subsets = from m in Enumerable.Range(0, 1 << arr.Length)
select
from i in Enumerable.Range(0, arr.Length)
where (m & (1 << i)) != 0
select arr[i];
You might be interested in checking out the GNU Scientific Library if you want to avoid maintenance costs. The actual process of summing longer sequences will become very expensive (more-so than generating a single permutation on a step basis), most architectures have SIMD/vector instructions that can provide rather impressive speed-up (I would provide examples of such implementations but I cannot post URLs yet).
Thanks Zach,
I am creating a Bank Reconciliation solution. I dropped your code into jsbin.com to do some quick testing and produced this in Javascript:
function f(numbers,ids, index, sum, output, outputid, find )
{
if (index == numbers.length){
var x ="";
if (find == sum) {
y= output + " } = " + sum + " " + outputid + " }<br/>" ;
}
return;
}
f(numbers,ids, index + 1, sum + numbers[index], output + " " + numbers[index], outputid + " " + ids[index], find);
f(numbers,ids, index + 1, sum, output, outputid,find);
}
var y;
f( [1.2,4,7,13,45,325,23,245,78,432,1,2,6],[1,2,3,4,5,6,7,8,9,10,11,12,13], 0, 0, '{','{', 24.2);
if (document.getElementById('hello')) {
document.getElementById('hello').innerHTML = y;
}
I need it to produce a list of ID's to exclude from the next matching number.
I will post back my final solution using vb.net
v=[1,2,3,4]#variables to sum
i=0
clis=[]#check list for solution excluding the variables itself
def iterate(lis,a,b):
global i
global clis
while len(b)!=0 and i<len(lis):
a=lis[i]
b=lis[i+1:]
if len(b)>1:
t=a+sum(b)
clis.append(t)
for j in b:
clis.append(a+j)
i+=1
iterate(lis,a,b)
iterate(v,0,v)
its written in python. the idea is to break the list in a single integer and a list for eg. [1,2,3,4] into 1,[2,3,4]. we append the total sum now by adding the integer and sum of remaining list.also we take each individual sum i.e 1,2;1,3;1,4. checklist shall now be [1+2+3+4,1+2,1+3,1+4] then we call the new list recursively i.e now int=2,list=[3,4]. checklist will now append [2+3+4,2+3,2+4] accordingly we append the checklist till list is empty.
set is the set of sums and list is the list of the original numbers.
Its Java.
public void subSums() {
Set<Long> resultSet = new HashSet<Long>();
for(long l: list) {
for(long s: set) {
resultSet.add(s);
resultSet.add(l + s);
}
resultSet.add(l);
set.addAll(resultSet);
resultSet.clear();
}
}
public static void main(String[] args) {
// this is an example number
long number = 245L;
int sum = 0;
if (number > 0) {
do {
int last = (int) (number % 10);
sum = (sum + last) % 9;
} while ((number /= 10) > 0);
System.err.println("s = " + (sum==0 ? 9:sum);
} else {
System.err.println("0");
}
}

Resources