I am building a tournament schedule with round robin style match order. I have an algorithm set up to build the matches, however the match order is not what I am looking for. I am struggling to develop an algorithm that will build the matches in my desired order. See example below with a 6 team bracket. Each vertical line represents a row in the tournament. The far left number represents the base team seed and who they will play in each round.
Note: The only thing that is really important to me is that the 1 and 2 seed play in the last round of the tournament. And preferably that 1 v 6, 2 v 5, 3 v 4 happens in the first round of the tournament. All other matches aren't as important. Thank you in advance for any help you can provide.
1: 6 5 4 3 2
2: 5 4 3 6 1
3: 4 6 2 1 5
4: 3 2 1 5 6
5: 2 1 6 4 3
6: 1 3 5 2 4
Here is my current code:
int numTeams = teamList.Count;
int rounds = (numTeams - 1);
int halfSize = numTeams / 2;
List<Team> teams = new List<Team>();
teams.AddRange(teamList); // Copy all the elements.
teams.RemoveAt(0); // To exclude the first team.
int teamSize = teams.Count;
for (int round = 0; round < rounds; round++)
{
int teamIdx = round % teamSize;
Team baseTeam1 = teams[teamIdx];
Team baseTeam2 = teamList[0];
// save each team to a match
for (int idx = 1; idx < halfSize; idx++)
{
int firstTeamIdx = (round + idx) % teamSize;
int secondTeamIdx = (round + teamSize - idx) % teamSize;
Team subTeam1 = teams[firstTeamIdx];
Team subTeam2 = teams[secondTeamIdx];
// save each team to a match
}
}
Sometimes asking the question helps figure out the answer. As it turns out, my current algorithm was creating what I wanted, just in opposite order. What I did to fix was create a new varible inside the first for loop called actualRound:
int actualRound = rounds - round; // this will reverse the round order
Related
I've a little trouble finding out how to linearly interpolate between two numbers with a defined number of intermediate steps.
Let's say I want to interpolate between 4 and 22 with 8 intermediate steps like so : Example
It's easy to figure out that it's x+2 here. But what if the starting value was 5 and the final value 532 with 12 intermediate steps? (In my special case I would need starting and ending value with 16 steps in between)
If you have two fence posts and you put k fence posts between them, you create k + 1 spaces. For instance:
| |
post1 post2
adding one posts creates two spaces
| | |
post1 post2
If you want those k + 1 spaces to be equal you can divide the total distance by k + 1 to get the distance between adjacent posts.
d = 22 - 4 = 18
k = 8
e = d / (k + 1) = 18 / 9 = 2
In your other case example, the answer is
d = 532 - 5 = 527
k = 12
e = d / (k + 1) = 527 / 13 ~ 40.5
I hesitate to produce two separate answers, but I feel this methodology is sufficiently unique from the other one. There's a useful function which may be exactly what you need which is appropriately called Mathf.Lerp().
var start = 5;
var end = 532;
var steps = 13;
for (int i = 0; i <= steps; i++) {
// The type conversion is necessary because both i and steps are integers
var value = Mathf.Lerp(start, end, i / (float)steps);
Debug.Log(value);
}
For actually doing the linear interpolation, use Mathf.MoveTowards().
For figuring out your maximum delta (i.e. the amount you want it to move each step), take the difference, and then divide it by the number of desired steps.
var start = 4;
var end = 22;
var distance = end - start;
var steps = 9; // Your example technically has 9 steps, not 8
var delta = distance / steps;
Note that this conveniently assumes your distance is a clean multiple of steps. If you don't know this is the case and it's important that you never exceed that number of steps, you may want to explicitly check for it. Here's a crude example for an integer. Floating point methods may be more complicated:
if (distance % delta > 0) { delta += 1; }
So for example we have 1, 5, and 10 and we want to interpolate between these with 12 points, we should get:
1.0000
1.7273
2.4545
3.1818
3.9091
4.6364
5.4545
6.3636
7.2727
8.1818
9.0909
10.0000
say we have 5, 10, and 4 and again 12 points, we should get:
5.0000
5.9091
6.8182
7.7273
8.6364
9.5455
9.4545
8.3636
7.2727
6.1818
5.0909
4.0000
This is a generalized solution that works by these principles:
Performs linear interpolation
It calculates a "floating point index" into the input array
This index is used to select 1 (if the fractional parts is very close to 0) or 2 numbers from the input array
The integer part of this index is the base input array index
The fractional part says how far towards the next array element we should move
This should work with whatever size input arrays and output collections you would need.
public IEnumerable<double> Interpolate(double[] inputs, int count)
{
double maxCountForIndexCalculation = count - 1;
for (int index = 0; index < count; index++)
{
double floatingIndex = (index / maxCountForIndexCalculation) * (inputs.Length - 1);
int baseIndex = (int)floatingIndex;
double fraction = floatingIndex - baseIndex;
if (Math.Abs(fraction) < 1e-5)
yield return inputs[baseIndex];
else
{
double delta = inputs[baseIndex + 1] - inputs[baseIndex];
yield return inputs[baseIndex] + fraction * delta;
}
}
}
It produces the two collections of outputs you showed in your question but beyond that, I have not tested it. Little error checking is performed so you should add the necessary bits.
The problem is an interpolation of two straight lines with different slopes given the end points and the intersection.
Interpolation is defined as following : In the mathematical field of numerical analysis, interpolation is a method of constructing new data points within the range of a discrete set of known data points.
I'm tired of people giving negative points for solutions to hard problems. This is not a simply problem, but a problem that require "thinking out of the box". lets looks at the solution for following input : 1 12 34
I picked these numbers because the results are all integers
The step size L (Lower) = distance of elements from 1 to 12 = 2
The step size H (Higher) = distance of elements from 12 to 34 = 4
So the answer is : 1 3 5 7 9 11 [12] 14 18 22 26 30 34
Notice the distance between the 6th point 11 and center is 1 (half of L)
Notice the distance between the center point 12 and the 7th point is 2 (half of H)
Finally notice the distance between the 6th and 7th points is 3.
My results are scaled exactly the same as the OPs first example.
It is hard to see the sequence with the fractional inputs the OP posted. If you look at the OP first example and calculate the step distance of the first 6 points you get 0.72. The last 6 points the distance is 0.91. Then calculate the distance from the 6th point to the center is .36 (half 0.72). Then center to 7th point 0.45 (half 0.91). Excuse me for rounding the numbers a little bit.
It is a sequence problem just like the in junior high school where you learned arithmetic and geometric sequences. Then as a bonus question you got the sequence 23, 28, 33, 42,51,59,68,77,86 which turns out to be the train stations on the NYC 3rd Ave subway system. Solving problems like this you need to think "Outside the Box" which comes from the tests IBM gives to Job Applicants. These are the people who can solve the Nine Point Problem : http://www.brainstorming.co.uk/puzzles/ninedotsnj.html
I did the results when the number of points is EVEN which in you case is 12. You will need to complete the code if the number of points is ODD.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace ConsoleApplication1
{
class Program
{
const int NUMBER_POINTS = 12;
static void Main(string[] args)
{
List<List<float>> tests = new List<List<float>>() {
new List<float>() { 1,5, 10},
new List<float>() { 5,10, 4}
};
foreach (List<float> test in tests)
{
List<float> output = new List<float>();
float midPoint = test[1];
if(NUMBER_POINTS % 2 == 0)
{
//even number of points
//add lower numbers
float lowerDelta = (test[1] - test[0])/((NUMBER_POINTS / 2) - .5F);
for (int i = 0; i < NUMBER_POINTS / 2; i++)
{
output.Add(test[0] + (i * lowerDelta));
}
float upperDelta = (test[2] - test[1]) / ((NUMBER_POINTS / 2) - .5F); ;
for (int i = 0; i < NUMBER_POINTS / 2; i++)
{
output.Add(test[1] + (i * upperDelta) + (upperDelta / 2F));
}
}
else
{
}
Console.WriteLine("Numbers = {0}", string.Join(" ", output.Select(x => x.ToString())));
}
Console.ReadLine();
}
}
}
Given the following:
for(int seed = 0; seed < 100; seed++) {
var random = new Random(seed);
var roll = (random.Next() % 6) + 1;
Console.Write(roll + " ");
}
I'm seeing a clear pattern in the output:
1 1 2 2 3 3 4 4 5 5 6 6 1 1 1 2 2 3 3 4 4 5 5 6 6
1 1 2 2 3 3 4 4 5 5 5 6 6 1 1 2 2 3 3 4 4 5 5 6 6
1 1 2 2 3 3 4 4 4 5 5 6 6 1 1 2 2 3 3 4 4 5 5 6 6
1 1 2 2 3 3 3 4 4 5 5 6 6 1 1 2 2 3 3 4 4 5 5 6 6
I do understand that recreating a new Random object every time with a sequential seed isn't the "proper" way of using the class, and that strictly speaking I should be keep the Random instance around, calling Next() on it each time.
However, my use case is that I need to be able to exit my program and restore the state at any moment, and continue the sequence of numbers.
I also need the user to be able to set a seed manually, so I was hoping to be able to do something like:
var random = new Random(userSeed + nextValueIndex);
var chosenValue = random.Next();
I've also tried random.Next(min, max), and it gives different results, but also in a clear pattern.
Clearly my approach isn't the right way to use the Random class, but what is, for my use case?
I understand that random number generation is a very complex topic, so while I'm sort of interested in an explanation of why this is happening, I'm most interested in a practical (easy?) solution ;-)
Here's my solution, which seems to work nicely. Rather than seeding Random with userSeed + index (where index counts from zero), I simply cache the exact result from Random as previousRandom, and then seed with userSeed + previousRandom. That way, I get nice big numbers as the seed, and it avoids the sequential pattern. (previousRandom is initialised as zero, but that's not a problem.)
So, this is roughly what my code looks like:
var nextSeed = userSeed + this.previousRandom;
var randomObj = new Random(nextSeed);
var nextRandomValue = randomObj.Next ();
var chosenValue = (nextRandomValue % randomRange) + rangeMin;
this.previousRandom = nextRandomValue;
return chosenValue;
The one remaining thing I should probably do is make sure that userSeed + previousRandom doesn't overflow (or overflows predictably), because previousRandom might get very close to int's upper bound (up to whatever range I allow for userSeed).
If you have a NxN matrix of positive integers, and you are asked to select exactly one element from each row and column, so that the sum of the selected elements is minimized, how can it be solved?
I think it is about Dynamic Programming. I have tried to minimize the time O(n!) using memoization:
Dictionary<byte[,], int>[] memo = new Dictionary<byte[,], int>[17];
int rec(byte[,] arr)
{
if (arr.Length == 1) return arr[0, 0];
int opt = find(arr);
if (opt != -1) return opt;
opt = 1 << 25;
for (int i = 0; i < arr.GetLength(1); ++i)
opt = Math.Min(opt, arr[0, i] + rec(divide(arr, i)));
add(arr, opt);
return opt;
}
This chooses an element from row 0 of the current matrix and then divides the matrix and calls itself recursively to solve the submatrix. Function divide divides the current matrix according to the selected element. The sub-matrix size is then (N-1)x(N-1). Function find performs linear search in memo[n], and add adds the solution to memo[n] But this is too slow as it will compare each matrix with other.
Do you have some inhancements? Is there a faster DP algorithm? Any help is appreciated
EXAMPLE
1 2 3 4
8 7 6 5
9 11 10 12
13 14 16 15
The optimal solution: 1 + 5 + 10 + 14
Steps:
7 6 5
11 10 12
14 16 15
11 10
14 16
14
This is actually the assignment problem. It can be solved in polynomial time using the Hungarian algorithm, among other methods.
What is an efficient way of generating N unique numbers within a given range using C#? For example, generate 6 unique numbers between 1 and 50. A lazy way would be to simply use Random.Next() in a loop and store that number in an array/list, then repeat and check if it already exists or not etc.. Is there a better way to generate a group of random, but unique, numbers?
To add more context, I would like to select N random items from a collection, using their index.
thanks
Take an array of 50 elements: {1, 2, 3, .... 50}
Shuffle the array using any of the standard algorithms of randomly shuffling arrays. The first six elements of the modified array is what you are looking for. HTH
For 6-from-50, I'm not too sure I'd worry about efficiency since the chance of a duplicate is relatively low (30% overall, from my back-of-the-envelope calculations). You could quite easily just remember the previous numbers you'd generated and throw them away, something like (pseudo-code):
n[0] = rnd(50)
for each i in 1..5:
n[i] = n[0]
while n[1] == n[0]:
n[1] = rnd(50)
while n[2] == any of (n[0], n[1]):
n[2] = rnd(50)
while n[3] == any of (n[0], n[1], n[2]):
n[3] = rnd(50)
while n[4] == any of (n[0], n[1], n[2], n[3]):
n[4] = rnd(50)
while n[5] == any of (n[0], n[1], n[2], n[3], n[4]):
n[5] = rnd(50)
However, this will break down as you move from 6-from-50 to 48-from-50, or 6-from-6, since the duplicates start getting far more probable. That's because the pool of available numbers gets smaller and you end up throwing away more and more.
For a very efficient solution that gives you a subset of your values with zero possibility of duplicates (and no unnecessary up-front sorting), Fisher-Yates is the way to go.
dim n[50] // gives n[0] through n[9]
for each i in 0..49:
n[i] = i // initialise them to their indexes
nsize = 50 // starting pool size
do 6 times:
i = rnd(nsize) // give a number between 0 and nsize-1
print n[i]
nsize = nsize - 1 // these two lines effectively remove the used number
n[i] = n[nsize]
By simply selecting a random number from the pool, replacing it with the top number from that pool, then reducing the size of the pool, you get a shuffle without having to worry about a large number of swaps up front.
This is important if the number is high in that it doesn't introduce an unnecessary startup delay.
For example, examine the following bench-check, choosing 10-from-10:
<------ n[] ------>
0 1 2 3 4 5 6 7 8 9 nsize rnd(nsize) output
------------------- ----- ---------- ------
0 1 2 3 4 5 6 7 8 9 10 4 4
0 1 2 3 9 5 6 7 8 9 7 7
0 1 2 3 9 5 6 8 8 2 2
0 1 8 3 9 5 6 7 6 6
0 1 8 3 9 5 6 0 0
5 1 8 3 9 5 2 8
5 1 9 3 4 1 1
5 3 9 3 0 5
9 3 2 1 3
9 1 0 9
You can see the pool reducing as you go and, because you're always replacing the used one with an unused one, you'll never have a repeat.
Using the results returned from that as indexes into your collection will guarantee that no duplicate items will be selected.
var random = new Random();
var intArray = Enumerable.Range(0, 4).OrderBy(t => random.Next()).ToArray();
This array will contain 5 random numbers from 0 to 4.
or
var intArray = Enumerable.Range(0, 10).OrderBy(t => random.Next()).Take(5).ToArray();
This array will contain 5 random numbers between 0 to 10.
int firstNumber = intArray[0];
int secondNumber = intArray[1];
int thirdNumber = intArray[2];
int fourthNumber = intArray[3];
int fifthNumber = intArray[4];
For large sets of unique numbers, put them in an List..
Random random = new Random();
List<int> uniqueInts = new List<int>(10000);
List<int> ranInts = new List<int>(500);
for (int i = 1; i < 10000; i++) { uniqueInts.Add(i); }
for (int i = 1; i < 500; i++)
{
int index = random.Next(uniqueInts.Count) + 1;
ranInts.Add(uniqueInts[index]);
uniqueInts.RemoveAt(index);
}
Then randomly generate a number from 1 to myInts.Count. Store the myInt value and remove it from the List. No need to shuffle the list nor look to see if the value already exists.
instead of using List use Dictionary!!
In case it helps anyone else, I prefer allocating the minimum number of items necessary. Below, I make use of a HashSet, which ensures that new items are unique. This should work with very large collections as well, up to the limits of what HashSet plays nice with.
public static IEnumerable<int> GetRandomNumbers(int numValues, int maxVal)
{
var rand = new Random();
var yieldedValues = new HashSet<int>();
int counter = 0;
while (counter < numValues)
{
var r = rand.Next(maxVal);
if (yieldedValues.Add(r))
{
counter++;
yield return r;
}
}
}
generate unique random nos from 1 to 40 :
output confirmed :
class Program
{
static int[] a = new int[40];
static Random r = new Random();
static bool b;
static void Main(string[] args)
{
int t;
for (int i = 0; i < 20; i++)
{
lab: t = r.Next(1, 40);
for(int j=0;j<20;j++)
{
if (a[j] == t)
{
goto lab;
}
}
a[i] = t;
Console.WriteLine(a[i]);
}
Console.Read();
}
}
sample output :
7
38
14
18
13
29
28
26
22
8
24
19
35
39
33
32
20
2
15
37