algorithms for tournament brackets (NCAA, etc.) - c#

I'm trying implement a bracket in my program (using C#/.NET MVC) and I am stuck trying to figure out some algorithm.
For example, I have a bracket like this with 8 entries (A,B,C,D,E,F,G,H)
I'm trying to figure out if there's an algorithmic way to
depending on # of entries, find # of
games per round
depending on # of entries, for a
specific game #, what is the
corresponding game # in the next
round?
For example, in this case, for 8 entries, the example are:
for round 1, there are 4 games. Round 2, 2 games. Round 3, 1 game
game 2 in round 1 corresponds to game 5 in round 2.
I also thought about storing this info in a table, but it seems overkill since it never changes, but here it is anyway:
Any help will be greatly appreciated!
Cheers,
Dean

C# code for the first part of your question:
// N = Initial Team Count
// R = Zero-Based Round #
// Games = (N / (2 ^ R)) / 2
public double GamesPerRound(int totalTeams, int currentRound) {
var result = (totalTeams / Math.Pow(2, currentRound)) / 2;
// Happens if you exceed the maximum possible rounds given number of teams
if (result < 1.0F) throw new InvalidOperationException();
return result;
}
The next step in solving part (2) is to know the minimum game number for a given round. An intuitive way to do that would be through a for loop, but there's probably a better method:
var totalTeams = 8;
var selectedRound = 2;
var firstGame = 1;
// If we start with round 1, this doesn't execute and firstGame remains at 1
for (var currentRound = 1; currentRound < selectedRound; currentRound++) {
var gamesPerRound = GamesPerRound(totalTeams, currentRound);
firstGame += gamesPerRound;
}

Quoting #Yuck who answered the first question perfectly.
C# code for the first part of your question:
// N = Initial Team Count
// R = Zero-Based Round #
// Games = (N / (2 ^ R)) / 2
public double GamesPerRound(int totalTeams, int currentRound) {
var result = (totalTeams / Math.Pow(2, currentRound)) / 2;
// Happens if you exceed the maximum possible rounds given number of teams
if (result < 1.0F) throw new InvalidOperationException();
return result;
}
Moving on to the second question:
//G = current game.
//T = total teams
//Next round game = (T / 2) + RoundedUp(G / 2)
//i. e.: G = 2, T = 8
//Next round game = (8 / 2) + RoundedUp(2 / 2) = 5
public int NextGame(int totalTeams, int currentGame) {
return (totalTeams / 2) + (int)Math.Ceiling((double)currentGame / 2);
}

I actually worked this out myself fairly recently and stumbled on (that is, I worked it out, but it has probably been discovered before) a neat recursive solution.
You start with your list of players, in a list that is sorted in seed order. This will be important later.
The overall algorithm consists of splitting the list of players into two and then creating two sub-tournaments. The winners of the two sub-tournaments will end up the grand final of the overall tournament.
Required Objects
Player
Name
Seed
Match
Home Player
Away Player
Next Match (pointer to the Match the winner goes to)
Splitting the Lists
Most tournaments put the top seeded player against the bottom seeded player in round one. In order to do this I used the following algorithm, but you could just put the first n / 2 players in one list and the rest in the other list to create a tournament where seeds 1 and 2 play off in round one (and seed 3 plays 4, 5 plays 6 etc).
I'll note here that the neat thing about having top seed play bottom seed is that with this algorithm if you don't have a power of two number of players, the top seed(s) will get a bye in the early rounds.
Take the first player and put them in the "left" list
Take the next two players (or the last player) and put them in the "right" list
Take the next two player and put them in the "left" list
Repeat from step 2 until there are no more players.
Of course, if there are only two players in the list you simply create a match between them and return.
Building the Tournament
So you start out with a list of say, 64 players. You split it into two lists of 32 players and recursively create two sub tournaments. The methods that you call recursively should return the Matches that represent the sub-tournament's grand final match (the semi-final of your overall tournament). You can then create a match to be the grand final of your overall tournament and set the nextMatch of the semi final matches to be this grand final.
Things to Consider
You'll need to break out of recursing if there are only two players in the list that's passed in.
If your split gives you a list of one, shouldn't recurse with it. Just create a sub-tournament with the other list (it should only have two players so will return with a match immediately), set the home team to be the single player and the nextMatch of the sub-tournament.
If you want to be able to keep track of rounds, you'll need to pass a recursion depth integer - increment it when you create a sub-tournament.
Hope this helps, let me know if you need any clarification :)

So basically its a elimination contest.
So just have List.
The algorithm will always put the first and second teams together if the number of teams is even. You then increase the counter by two and repeat.
If the number of teams is odd do pretty much the samething except you randomly select a winner of the "first around" and put it against the odd team.
After the first round you repeat the algorithm the same way.
A+1
C+1
...
For example, I have a bracket like
this with 8 entries (A,B,C,D,E,F,G,H)
You should be able to figure out how to parse this. This seems like a homework question.

Consider renumbering the games (you can always renumber them back afterwards)
if the final is 1
semis are 2,3
the problem is then has well-published solutions: ahnentafel (German for ancestor table) has been used for a long time by genealogists - http://en.wikipedia.org/wiki/Ahnentafel
one interesting part of this is the binary notation of the game # gives a lot of information as to the structure of the tournament and where in the tree the match is.
Also note that as every match knocks out 1 competitor, for n competitors there will be n-1 matches

Related

Efficient approach to get all elements within a range in a 2d array?

Consider the following 2 dimensional jagged array
[0,0] [0,1] [0,2]
[1,0] [1,1]
[2,0] [2,1] [2,2]
Lets say I want to know all elements that fall within a certain range for example [0,0]-[2,0], I would like a list of all of those elements, what would be the best approach for achieving this and are there any pre-existing algorithms that achieve this?
I have attempted to implement this in C# but didn't get much further than some for loops.
The example below better provides further detail upon what I would like to achieve.
Using the array defined above, lets say the start index is [0,0] and the end index of the range is [2,1]
I would like to create a method that returns the values of all the indexes that fall within this range.
Expected results would be for the method to return the stored values for the following index.
[0,0] [0,1] [0,2] [1,0] [1,1] [2,0] [2,1]
If the 2d array is "sorted", meaning that as you go from left to right in each 1d array the y increases and as you go from up to down the x increases, you can find the first point and the last point that you need to report using binary searches in total time of O(logn), and after that report every point between those 2 points in O(k) where k is the number of points that you need to report (notice that you the tome complexity will be Omega(k) in every algorithm).
If the 2D array is not sorted and you just want to output all the pairs between pair A and pair B:
should_print = False
should_stop = False
for i in range(len(2dArray)):
for j in range(len(2dArray[i]))
should_print = (should_print or (2dArray[i][j] == A))
if should_print:
print(2dArray[i][j])
should_stop = (2dArray[i][j] == B)
if should_stop:
break
if should_stop:
break
If you just have n general 2d points and you wish to answer the query "find me all the points in a given rectangle", there are 2 data structures that can help you - kd trees and range trees. These 2 data structures provide you a good query time but they are a bit complicated. I am not sure what is your current level but if you are just starting to get into DS and algorithms these data structures are probably an overkill.
Edit (a bit about range trees and kd trees):
First I'll explain the basic concept behind range trees. Lets start by trying to answer the range query for 1D points. This is easy - just build a bst (balanced search tree) and with it you can answer queries in O(logn + k) where k is the number of points being reported. It takes O(nlogn) time to build the bst and it take O(n) space.
Now, let us try to take this solution and make it work for 2D. We will build a bst for the x coordinates of the points. For each node t in the bst denote all the points in the subtree of t by sub(t). Now, for every node t we will build a bst for the y coordinates of the points sub(t).
Now, given a range, we will for find all the subtrees contained in the x range using the first bst, and for each subtree we will find all the points contained in the y range (note that the bst corresponding the the subtree of sub(t) is saved at the node t).
A query takes O(log^2n) time. Building the DS takes O(nlog^2n) time and finally, it takes O(nlogn) space. I'll let you prove these statements. With more work the query time can be reduced to O(logn) and the building time can be reduced to O(nlogn). You can read about it here: http://www.cs.uu.nl/docs/vakken/ga/2021/slides/slides5b.pdf.
Now a word about KD trees. The idea is to split the 2D sapce in the middle with a vertical line, after that split each side in the middle with a horizontal line and so on. The query time in this DS will take O(sqrt(n)), the building time is O(nlogn) and the space it takes is O(n). You can read more about this DS here: http://www.cs.uu.nl/docs/vakken/ga/2021/slides/slides5a.pdf

How do I store information for weighed graph without running out of memory?

So I've got a task with cities and roads. Each road between cities has it's price. There are lots of cities and some of them are connected with roads having different prices. How do I store that information?
Information is read from file and then put into a Two-dimensional array. numbers{0} and numbers{1} contain the numbers of two connected cities while numbers{2} is the price of the road.
So indexes of this array are the numbers of the cities and the number under those indexes is the price.
int[,] graph = new int[cities, cities];
for (int i = 0; i < roads; i++)
{
numbers = ReadFromFile(input);
graph[numbers[0] - 1, numbers[1] - 1] = numbers[2];
graph[numbers[1] - 1, numbers[0] - 1] = numbers[2];
}
It works, but a big part from the tests it has to pass are failed. And the reason is that at some point it has to store 5000 * 5000 values for 5000 cities and it runs out of memory. What cain I do to avoid this? I thought about other options but nothing comes to mind that is better than this one.
A snapshot
Before doing anything else try converting the project to work in x64 architecture instead of "Any CPU" or "Win32". This could make some memory problems simply go away.
Ideally you should use "sparse arrays" or "sparse matrices". There are some projects on the net, but they could be unwieldy. Next best thing is to simulate a sparse array using a dictionary and two single dimensional arrays instead of the big matrix.
The dictionary has Tuple<int, int> as key (two ints are coordinates of a cell) and road prices as value (if only one road can connect two cities then value is an int, for multiple roads between two cities it's List<int>).
Two single dimensional arrays are used to find non-empty cells in the dictionary. One array for each coordinate, so both with size 5000, they contain a List<int> list of all coordinates in another axis where there are non-empty cells. Depending on your search algorithm you might need only one such array, for x-axis for example (and the other for y-axis is not needed).
Assuming that every city is connected to every other city by 3 or less different roads. For each road, you need to store 3 items ( source, destination and cost ) Assume that an item requires 4 bytes of storage.
5000 * 5000 * 3 * 4 = 3 * 10^8
That is 300 Megabytes of storage.
Any modern computer should have no problem storing this - memory is usually measured these days in Gigabytes.
You have some problem with your computer!

Predicting the amount of parents in a binary tree

I'm trying to predict the amount of parents in a Binary tree given that it all you know is the amount of leaves, and its a balanced binary tree.
Currently, my code runs like this:
int width = exits;
int amountOfParents = 0;
do
{
width -= 2;
AmountOfParents++;
} while (width > 0);
The basic premise of the code is that it will take all the child, and find the number of parents for them. Do this iteratively until you reach the root. However, the problem comes in when the height of the tree is uneven.
This solution gives correct number of parents up till 5. When it hits 6, the binaray tree creates another parent node, so there should be 4, but it gives 3. I know why it gives 3, but I don't know how to fix it.
Edit: I just had another idea. What if I find the closest perfect square number perfectly balanced tree, and than individually find the unaccounted? Trying now.
The formula is log2(exits) * 2 + 1
C#: Math.Ceiling(Math.Log(x) / Math.Log(2)) * 2 + 1;
But it has to be perfectly balanced indeed
So since I'm doing the inverse of square numbers, your idea of the square numbers could work.
I tried it with several different methods, but this seems to be the best one.
You take the all the child and group them into pairs. Put the pairs into a list and do the same thing again. If there is an odd number of pairs, just put him into the list. He will get handled in later iterations due to the nature of it.

Interview - Write a program to remove even elements

I was asked this today and i know the answer is damn sure simple but he kept me the twist to the last.
Question
Write a program to remove even numbers stored in ArrayList containing 1 - 100.
I just said wow
Here you go this is how i have implemented it.
ArrayList source = new ArrayList(100);
for (int i = 1; i < 100; i++)
{
source.Add(i);
}
for (int i = 0; i < source.Count; i++)
{
if (Convert.ToInt32(source[i]) % 2 ==0)
{
source.RemoveAt(i);
}
}
//source contains only Odd elements
The twist
He asked me what is the computational complexity of this give him a equation. I just did and said this is Linear directly proportional to N (Input).
he said : hmmm.. so that means i need to wait longer to get results when the input size increases am i right? Yes sirr you are
Tune it for me, make it Log(N) try as much as you can he said. I failed miserably in this part.
Hence come here for the right logic, answer or algorithm to do this.
note: He wanted no Linq, No extra bells and whistles. Just plain loops or other logic to do it
I dare say that the complexity is in fact O(N^2), since removal in arrays is O(N) and it can potentially be called for each item.
So you have O(N) for the traversal of the array(list) and O(N) for each removal => O(N) * O(N).
Since it does not seem clear, I'll explain the reasoning. At each step a removal of an item may take place (assuming the worst case in which every item must be removed). In an array the removal is done by shifting. Hence, to remove the first item, I need to shift all the following N-1 items by one position to the left:
1 2 3 4 5 6...
<---
2 3 4 5 6...
Now, at each iteration I need to shift, so I'm doing N-1 + N-2 + ... + 1 + 0 shifts, which gives a result of (N) * (N-1) / 2 (arithmetic series) giving a final complexity of O(N^2).
Let's think it this way:
The number of delete actions you are doing is, forcely, the half of array lenght (if the elements are stored in array). So the complexity is at least O(N) .
The question you received let me suppose that your professor wanted you to reason about different ways of storing the numbers.
Usually when you have log complexity you are working with different structures, like graphs or trees.
The only way I can think of having logartmic complexity is having the numbers stored in a tree (ordered tree, b-tree... we colud elaborate on this), but it is actually out of the constraints of your exam (sotring numbers in array).
Does it make sense to you?
You can get noticeably better performance if you keep two indexes, one to the current read position and one to the current write position.
int read = 0
int write = 0;
The idea is that read looks at each member of the array in turn; write keeps track of the current end of the list. When we find a member we want to delete, we move read forwards, but not write.
for (int read = 0; read < source.Count; read++) {
if (source[read] % 2 != 0) {
source[write] = source[read];
write += 1;
}
}
Then at the end, tell the ArrayList that its new length is the current value of `write'.
This takes you from your original O(n^2) down to O(n).
(note: I haven't tested this)
Without changing the data structure or making some assumption on the way items are stores inside the ArrayList, I can't see how you'll avoid checking the parity of each and every member (hence at least O(n) complexity). Perhaps the interviewer simply wanted you to tell him it's impossible.
If you really have to use an ArrayList and actively have to remove the entries (instead if not adding them in the first place)
Not incrementing by i + 1 but i + 2 will remove your need to check if it is odd.
for (int i = source.Count - 1 ; i > 0; i = i i 2)
{
source.RemoveAt(i);
}
Edit: I know this will only work if source contains the entries from 1-100 in sequential order.
The problem with the given solution is that it starts from the beginning, so the entire list must be shifted each time an item is removed:
Initial List: 1, 2, 3, 4, 5, ..., 98, 99
/ / / /// /
After 1st removal: 1, 3, 4, 5, ..., 98, 99, <empty>
/ /// / /
After 2nd removal: 1, 3, 5, ..., 98, 99, <empty>, <empty>
I've used the slashes to try to show how the list shifts after each removal.
You can reduce the complexity (and eliminate the bug I mentioned in the comments) simply by reversing the order of removal:
for (int i = source.Count-1; i >= 0; --i) {
if (Convert.ToInt32(source[i]) % 2 == 0) {
// No need to re-check the same element during the next iteration.
source.RemoveAt(--i);
}
}
It is possible IF you have unlimited parallel threads available to you.
Suppose that we have an array with n elements. Assign one thread per element. Assume all threads act in perfect sync.
Each thread decides whether its element is even or odd. (Time O(1).)
Determine how many elements below it in the array are odd. (Time O(log(n)).)
Mark a 0 or 1 in an second array depending whether you are even or odd at the same index. So each one is a count of odds at that spot.
If your index is odd, add the previous number. Now each entry is a count of odds in the current block of 2 up to yourself
If your index mod 4 is 2, add the value at the index below, if it is 3, add the answer 2 indexes below. Now each entry is a count of odds in the current block of 4 up to yourself.
Continue this pattern with blocks of 2**i (if you're in the top half add the count for the bottom half) log2(n) times - now each entry in this array is the count of odds below.
Each CPU inserts its value into the correct slot.
Truncate the array to the right size.
I am willing to bet that something like this is the answer your friend has in mind.

Finding a pattern within a string variable

I need to create a heads or tails project where the computer will guess randomly up to 5 times, but on the sixth time it will look into the playersGuessHistory variable setup as a string to see if it can find a match for a pattern of 4 entires. If there is a pattern found the computer will guess the next character after the pattern.
For example, given the sequence HHTTH the pattern is HHTT so the computer would guess H for the sixth turn. My only problem is that I'm having difficulty setting up the project so that it will look through the playersguesshistory and find the patterns and guess the next character in the history. Any suggestions?
Create a List<string> and throw the history into this, so that each item in the list is a string of 4 characters (like you show in your text). Then when the computer should guess select the items (there should be several) from the list that starts with (myList.StartsWith - method) your string, then you should sum up the amount of times that H is the next character, and the amount of times that T is the next character - calculate the probability of each of them and let the computer choose the one with the highest probability...
Does it make sense?
This is a little snippet based on what I understand of your requirement. The below method will return a string of guesses of 'H' heads or 'T' tails. The first 5 guesses are random, and then if any sequence of 4 guesses is HHTT the final guess will be 'H'.
static string HeadsOrTails()
{
string guessHistory = String.Empty;
// Guess heads or tails 5 times
Random random = new Random();
for (int currentGuess = 0; currentGuess < 5; currentGuess++)
{
if (random.Next(2) == 0)
guessHistory += 'H';
else
guessHistory += 'T';
}
// Analyse pattern of guesses
if (guessHistory.Substring(0, 4) == "HHTT" || guessHistory.Substring(1, 4) == "HHTT")
{
// If guess history contains HHTT then make the 6th guess = H
guessHistory += 'H';
}
return guessHistory;
}
This is a very simple implementation and will only work for 5 random initial guesses, but it should be quite easy to enhance as needed.
First of all, if the heads and tails are really random, like results from flipping an actual coin, this task is pointless. The computer will always get the next throw right with probability 1/2, regardless of any perceived patters in the history. (See "Independence".)
Now, if the heads and tails are not really random (e.g. they are created by a person calling heads or tails in a way he thinks is random), then we can maybe get the computer to have a higher success quote than 1/2.
I'd try the following: To start, check how often in the history.
heads are followed by heads
heads are followed by tails
and use these number for a guess on the transition probability H->H and H->T, do the same with the tails, and guess the next outcome based on the last one, choosing whatever seems more probable..
Says in the sequence "HHHTH", you find
- H->H: 2 of 3
- H->T: 1 of 3
- T->H: 1 of 1
Since the last throw came up heads, the computer should choose heads as the guess for the next throw.
Now, you can experiment with taking longer parts of the history into account, by counting the transitions "HH->T" and so on and try to improve your success rate.

Categories

Resources