Load Balancing of values into 8 "silos" - c#

I've got a problem I can't seem to crack. It's not that easy to explain so I'll do my best :
I have a really big array of values I have already sorted :
[ 2, 8, 26, ..., 1456, 1879, ..., 7812, 9614, ..., 20 408, 26 584 ]
I have 8 empty "silos" (kind of like an array) with unlimited capacity.
My goal is to fill those silo with all my values in order to make them as balanced as possible.
When I say "balanced", I mean that I want the sum of all the values in a silo to be almost equal to one another.
For example, if my silo 1 has a total sum of 52 000 and my silo 8 has a sum of 30 000 then it's not good. I'd rather have something like 41 000 and 43 500 if possible.
I've already done a round Robin, but it doesn't seem precise enough because I get a quite big difference between my silos.
I've looked up bin-packing also but it doesn't seem appropriate to me.
Thank you for any help or advice you may provide!

Optimization problems are never easy, but since you want to minimize the deviation from the average you simply iterate your values from highest to lowest value and add it to the silo with the lowest sum. That way you don't waste too much time on optimization and should (depending on your values) have a relatively good result.
// Generate some random data
int[] values = new int[1000];
Random r = new Random();
for (int i = 0; i < values.Length; i++)
{
values[i] = r.Next(1, 30000);
}
// Initialize silos
const int siloCount = 8;
List<int>[] result = new List<int>[siloCount];
for (int i = 0; i < siloCount; i++)
{
result[i] = new List<int>();
}
int[] sums = new int[siloCount];
int[] indices = Enumerable.Range(0, siloCount).ToArray();
// Iterate all values in descending order
foreach (int value in values.OrderByDescending(i => i).ToList())
{
// Find silo with lowest sum (or one of them)
int siloIndex = indices.First(i => sums[i] == sums.Min());
// Add to collection and sum - so we don't have to call .Sum() every iteration
sums[siloIndex] += value;
result[siloIndex].Add(value);
}
Debug.WriteLine(String.Join("\r\n", result.Select(s => s.Sum())));
.Net Fiddle

Related

I need some help to complete this code of non-duplicate random numbers

I need some help to do my homework. I should write non-duplicate random numbers. I'm able to show random numbers but I don't know about non-duplicate.
Here's my code:
Random r = new Random();
for (int i = 0; i < 40; i++)
{
int temp = r.Next(0, 100);
Console.WriteLine(temp);
}
What do I need to do to generate non-duplicate number?
Note that this answer only deals with (relatively) small, pre-determined sets.
The reason the other (simple) solution is inefficient is this: you want to generate 100 random numbers between 0 and 99. You get to the point where you have generated 90 random numbers, and just need 10 more.
The problem is that you're still generating numbers between 0 and 99 every time, except now your chance of finding a number that hasn't already been generated is 1 in 10. So 9 of every 10 numbers you generate has already been added to the list.
Once you get down to just needing 1 number, your chance of generating the remaining 1 that hasn't already been generated is 1 in 100. So for every 100 numbers you generate, only 1 of them will be the last possible number.
I'm sure this is simplifying things given that the Random class is pseudo-random (i.e. it's an algorithm that appears random), but this does explain your situation and why the other answer will be slower.
An improved solution would be this:
// Add all of the numbers 0 to 100 to a list
var availableNumbers = new List<int>();
for (int i = 0; i < 100; ++i)
{
availableNumbers.Add(i);
}
Random random = new Random();
for (int i = 0; i < 40; ++i)
{
// Choose a random position in the available numbers list
var idx = random.Next(0, availableNumbers.Count);
// Print the number from this position in the list
Console.WriteLine(availableNumbers[idx]);
// Remove the item at this position
availableNumbers.RemoveAt(idx);
}
Because we start with a list of all available numbers, we are able to choose numbers from it at random. Removing items from the available numbers list means that they are not available to be chosen a second time. We no longer have to try many times to find an unused number, as removing them when we select them ensures that all of the numbers in the available numbers list are always only unused numbers.
You may use a HashSet to store the numbers and make sure there are no duplicates. Here's an example:
HashSet<int> numbers = new HashSet<int>();
Random r = new Random();
for (int i = 0; i < 40; i++)
{
int temp;
do
{
temp = r.Next(0, 100);
} while (numbers.Add(temp) == false); // If the `.Add()` method returns false,
// that means the number already exists.
// So, we try to generate another number.
Console.WriteLine(temp);
}

Find the unique sum of integers from an dynamic array of numbers

I am facing a very difficult situation, suppose I have a array of dynamic numbers. The condition is the array may contain 10 numbers to 20 numbers. It can contain 10, 12, 14, ... to 20 integers. Now based on the ArrayList.Count(), I am going to choose 3(if array contains 10 integers) to 6 (if array contain 20 integers) numbers out of this array, and add those numbers. say that number is "X".
Now I have to check if there exist any three integers in the list whose sum is equal to X, if its equal, then again I have to repeat the same procedure until I find a unique sum from the list.
So how can I do it? The best part is all the numbers in the array is unique, there is no repeat of the numbers in the array.
First Idea
I though of one idea, for 3 numbers, Suppose I generate a unique number.
foreach (var i in List) // values of i = 1, 5, 8 (Assume)
{
sum += listOfUniqueIntegers[i];
}
// Fix the first element as List[i]
for (int i = 0; i < List.Count()-2; i++)
{
// Fix the second element as List[j]
for (int j = i+1; j < List.Count()-1; j++)
{
// Now look for the third number
for (int k = j+1; k < List.Count(); k++)
{
if (List[i] + List[j] + List[k] == sum)
{
// Here I will again create one more unique value
// and assign it to sum and repeat i = 0, j = 0, k = 0;
}
}
}
}
But the problem with this approach is its time complexity os n^3 so if I have to generate a sum from 6 numbers when List size is 20, it will be n^6, which is not expected.
Second idea
I though I can sort the List, but then what logic shall I use to choose 3 integers so that it's sum is unique in the List.
Lets say I sort the list and choose three smallest number or choose from the sorted list 3rd 3+1=4 th and 3+2=5th element, and sum=List[3]+List[4]+List[5];
this is also not expected, any pattern to choose three numbers is not suggested. It should be randomly chosen and the sum should be unique.
So I am not getting any idea to generate a optimal solution for this.
Can anybody please help me.
Just use the 3 largest numbers.

How to sort first M elements in N length array?

I have some tasks about sorting arrays in C#. I've been trying everything I could think of - no luck.
The task is to sort an array of integers by known sorting algorithms (insertion, selection, bubble, quick). Thing is, I have to sort ONLY the smallest M elements.
Example: I have an array of 7 elements 2 9 8 3 4 15 11 and I need to sort the smallest 3 elements so that my array becomes 2 3 4 9 8 15 11.
Please help, I can't seem to find anything neither here in SO, nor anywhere through Google. I don't ask to do all the algorithms for me, I just need one of those just to get hold on how's that possible.
E: Thank you for your thoughts. I've reviewed all of your recommendations and have accomplished to make an insertion sort like that:
static int[] insertSort(int[] arr, out int swaps, out int checks) {
int step = 0;
swaps = 0;
checks = 0;
for (int i = 0; i < arr.Length; i++) {
int min = arr[i], minind = i;
for (int j = i + 1; j < arr.Length; j++) {
checks++;
if (arr[j] < min) {
min = arr[j];
minind = j;
}
}
int temp = arr[minind];
if (step < M) {
for (int j = minind; j > i; j--) {
swaps++;
arr[j] = arr[j - 1];
}
arr[i] = temp;
swaps++;
step++;
}
}
return arr;
}
Swaps and checks - requirement for my application.
P.S. I've seen many times that SO doesn't like to do homework for someone. That's why I haven't asked for code, I've just asked for thoughts on how to accomplish that.
Thanks again for those who have helped me out here.
Since there is no efficiency limitations:
Set i to 0.
Look for the minimum among the not sorted elements.
Insert it into the position i, shift the array.
Increment i.
Repeat M times.
Complexity is O(N * M).
Without seeing your implementation, this is hard to answer. There are many ways to do this, and most are straight-forward.
Here are a few ideas though:
Create a "temporary" array that only holds the numbers to sort, sort it, then replace in original array (probably a sub-optimal solution)
Use a for loop that iterates the number of times you need (3 or whatever). This is probably the best solution
Post your code here on SO and some naive person will probably give you a solution so you don't have to do your schoolwork yourself. (This is a lazy and unbecoming solution)
I think here is what you are looking for, this is an example sorting of array ascending based on specific indixes.
int startIndex=2;
int endIndex=5;
int[] elements=new int[7];
elements[0]=2;
elements[1]=9;
elements[2]=8;
elements[3]=3;
elements[4]=4;
elements[5]=15;
elements[6]=11;
for (int a=startIndex-1;a<endIndex;a++){
for(int b=startIndex-1;b<endIndex;b++){
if (elements[a]<elements[b]){
int temp =elements[a];
elements[a]=elements[b];
elements[b]=temp;
}
}
}
for (int c=0;c<elements.Length;c++){
Console.Write(elements[c]+",");
}
Just change the "<" to ">" if you want to sort it desc.
You'd want to take a look at what sorting algorithm you're required to use. Say for example we're using one that uses a for loop. Most cases you'd see something like this
for(int i = 0; i < arrayName.length(); i++)
{}
In your case, just change the parameters of the for loop
for(int i = 0; i < M; i++)
{}
Where M is less than arrayName.length(); and is the number of positions from the beginning you would like to sort.
The rest of the array, untouched, should remain the same.
Couple things. Most sorting algorithms use array.length as the maximum range.
Could you just use m there instead? ie
for (int i = 0; i < m; i++)
Also, you could use a temporary array of the first m characters, sort it, then reassign.
int[] temp;
for (int i = 0; i < m; i++)
{
temp[i] = realArray[i];
}
//sort, then
for (int i = 0; i < m; i++)
{
realArray[i] = temp[i];
}
I would sort the full array and put it into the an other one.
Truncate the new array to only keep the smallest x elements.
Get the largest number from that array (in your example, 4).
Loop through the initial array and append all numbers that are higher.
Input: 2 9 8 3 4 15 11
Sort all: 2 3 4 8 9 11 15
Truncate: 2 3 4
Get highest value from this array (4)
Loop through original array and append
Is 2 higher than 4? no
Is 9 higher than 4? yes, append (we now have: 2 3 4 9)
Is 8 higher than 4? yes, append (we now have: 2 3 4 9 8)
Is 3 higher than 4? no
Is 4 higher than 4? no
Is 15 higher than 4? yes, append (we now have: 2 3 4 9 8 15)
Is 11 higher than 4? yes, append (we now have: 2 3 4 9 8 11)
*This is not the most efficient way and might cause problems if you have duplicate numbers
Any prescriptions on using LINQ?
int a[] = new int[] {2, 9, 8, 3, 4, 15, 11};
const int M = 5;
a = a.Take(M).OrderBy(e => e).ToArray(); // EDIT: Added .ToArray()

How to generate a non-growing (int) random array c#?

I'm trying to make a Integer (int) array with random numbers NOT growing.
For example: 3 10 5 9 20
But NOT: 3 5 9 10 20 (because they just grow)
I'm using Random class with this code (but I always get a growing list like in the second example):
int[] array1 = new int[5];
Random random_istance = new Random();
for (int i=0;i<5;i++)
{
array1[i] = random.Next(0,999999);
}
I also tried with a code like (I know it is horrible programming) :
int[] array1 = new int[5];
Random random_istance = new Random();
for (int i=0;i<5;i++)
{
random = new Random(x-y*z); // re-instantation
array1[i] = random.Next(0,999999); // x,y and z are variable defined outside
}
(*) My final goal is to get an array of random int between 0 and 999999 but some are to not to be in a sequence (because later I'm going to apply an algorithm to order the array and would not make sense to order a already-ordered array).
Moreover I have to create ANOTHER array with elements just DECREASING (so one random array , and one decreasing array).
Any idea how to salve at least first problem (*)?
Thanks in advance for any help.
One way to ensure that your array is not sorted from low to high is by ordering it randomly when you detect its ordered based on the value, something like:
// while the array is sorted
var sortedCopy = array1.ToList();
sortedCopy.Sort();
while (array1.SequenceEqual(sortedCopy))
{
Array.Sort(array1, new Comparison<int>((left, right) => random.Next(-1, 1)));
}
You can shuffle array after generating:
for (int i = 0; i < array1.Length; i++)
{
array1 = array1.OrderBy(c => random_istance.Next()).ToArray();
}
Well, I don't know if this would be a good solution, but you may try this:
Create random array with desired size.
Sort this array ascending.
Swap random elements i times, where i is a random number > 0.
To get decreasing numbers, create random array and just sort it descending.
Edit Of course it is possible, that you will end up with unchanged sequention if i is even. I think it is enough to swap elements i times, where i is greater than 0 and odd.

Efficient algorithm to get primes between two large numbers

I'm a beginner in C#, I'm trying to write an application to get primes between two numbers entered by the user. The problem is: At large numbers (valid numbers are in the range from 1 to 1000000000) getting the primes takes long time and according to the problem I'm solving, the whole operation must be carried out in a small time interval. This is the problem link for more explanation:
SPOJ-Prime
And here's the part of my code that's responsible of getting primes:
public void GetPrime()
{
int L1 = int.Parse(Limits[0]);
int L2 = int.Parse(Limits[1]);
if (L1 == 1)
{
L1++;
}
for (int i = L1; i <= L2; i++)
{
for (int k = L1; k <= L2; k++)
{
if (i == k)
{
continue;
}
else if (i % k == 0)
{
flag = false;
break;
}
else
{
flag = true;
}
}
if (flag)
{
Console.WriteLine(i);
}
}
}
Is there any faster algorithm?
Thanks in advance.
I remember solving the problem like this:
Use the sieve of eratosthenes to generate all primes below sqrt(1000000000) = ~32 000 in an array primes.
For each number x between m and n only test if it's prime by testing for divisibility against numbers <= sqrt(x) from the array primes. So for x = 29 you will only test if it's divisibile by 2, 3 and 5.
There's no point in checking for divisibility against non-primes, since if x divisible by non-prime y, then there exists a prime p < y such that x divisible by p, since we can write y as a product of primes. For example, 12 is divisible by 6, but 6 = 2 * 3, which means that 12 is also divisible by 2 or 3. By generating all the needed primes in advance (there are very few in this case), you significantly reduce the time needed for the actual primality testing.
This will get accepted and doesn't require any optimization or modification to the sieve, and it's a pretty clean implementation.
You can do it faster by generalising the sieve to generate primes in an interval [left, right], not [2, right] like it's usually presented in tutorials and textbooks. This can get pretty ugly however, and it's not needed. But if anyone is interested, see:
http://pastie.org/9199654 and this linked answer.
You are doing a lot of extra divisions that are not needed - if you know a number is not divisible by 3, there is no point in checking if it is divisible by 9, 27, etc. You should try to divide only by the potential prime factors of the number. Cache the set of primes you are generating and only check division by the previous primes. Note that you do need to generate the initial set of primes below L1.
Remember that no number will have a prime factor that's greater than its own square root, so you can stop your divisions at that point. For instance, you can stop checking potential factors of the number 29 after 5.
You also do can increment by 2 so you can disregard checking if an even number is prime altogether (special casing the number 2, of course.)
I used to ask this question during interviews - as a test I compared an implementation similar to yours with the algorithm I described. With the optimized algorithm, I could generate hundreds of thousands of primes very fast - I never bothered waiting around for the slow, straightforward implementation.
You could try the Sieve of Eratosthenes. The basic difference would be that you start at L1 instead of starting at 2.
Let's change the question a bit: How quickly can you generate the primes between m and n and simply write them to memory? (Or, possibly, to a RAM disk.) On the other hand, remember the range of parameters as described on the problem page: m and n can be as high as a billion, while n-m is at most a million.
IVlad and Brian most of a competitive solution, even if it is true that a slower solution could be good enough. First generate or even precompute the prime numbers less than sqrt(billion); there aren't very many of them. Then do a truncated Sieve of Eratosthenes: Make an array of length n-m+1 to keep track of the status of every number in the range [m,n], with initially every such number marked as prime (1). Then for each precomputed prime p, do a loop that looks like this:
for(k=ceil(m/p)*p; k <= n; k += p) status[k-m] = 0;
This loop marks all of the numbers in the range m <= x <= n as composite (0) if they are multiple of p. If this is what IVlad meant by "pretty ugly", I don't agree; I don't think that it's so bad.
In fact, almost 40% of this work is just for the primes 2, 3, and 5. There is a trick to combine the sieve for a few primes with initialization of the status array. Namely, the pattern of divisibility by 2, 3, and 5 repeats mod 30. Instead of initializing the array to all 1s, you can initialize it to a repeating pattern of 010000010001010001010001000001. If you want to be even more cutting edge, you can advance k by 30*p instead of by p, and only mark off the multiples in the same pattern.
After this, realistic performance gains would involve steps like using a bit vector rather than a char array to keep the sieve data in on-chip cache. And initializing the bit vector word by word rather than bit by bit. This does get messy, and also hypothetical since you can get to the point of generating primes faster than you can use them. The basic sieve is already very fast and not very complicated.
One thing no one's mentioned is that it's rather quick to test a single number for primality. Thus, if the range involved is small but the numbers are large (ex. generate all primes between 1,000,000,000 and 1,000,100,000), it would be faster to just check every number for primality individually.
There are many algorithms finding prime numbers. Some are faster, others are easier.
You can start by making some easiest optimizations. For example,
why are you searching if every number is prime? In other words, are you sure that, given a range of 411 to 418, there is a need to search if numbers 412, 414, 416 and 418 are prime? Numbers which divide by 2 and 3 can be skipped with very simple code modifications.
if the number is not 5, but ends by a digit '5' (1405, 335), it is not prime bad idea: it will make the search slower.
what about caching the results? You can then divide by primes rather by every number. Moreover, only primes less than square root of the number you search are concerned.
If you need something really fast and optimized, taking an existing algorithm instead of reinventing the wheel can be an alternative. You can also try to find some scientific papers explaining how to do it fast, but it can be difficult to understand and to translate to code.
int ceilingNumber = 1000000;
int myPrimes = 0;
BitArray myNumbers = new BitArray(ceilingNumber, true);
for(int x = 2; x < ceilingNumber; x++)
if(myNumbers[x])
{
for(int y = x * 2; y < ceilingNumber; y += x)
myNumbers[y] = false;
}
for(int x = 2; x < ceilingNumber; x++)
if(myNumbers[x])
{
myPrimes++;
Console.Out.WriteLine(x);
}
Console.Out.WriteLine("======================================================");
Console.Out.WriteLine("There is/are {0} primes between 0 and {1} ",myPrimes,ceilingNumber);
Console.In.ReadLine();
I think i have a very fast and efficient(generate all prime even if using type BigInteger) algorithm to getting prime number,it much more faster and simpler than any other one and I use it to solve almost problem related to prime number in Project Euler with just a few seconds for complete solution(brute force)
Here is java code:
public boolean checkprime(int value){ //Using for loop if need to generate prime in a
int n, limit;
boolean isprime;
isprime = true;
limit = value / 2;
if(value == 1) isprime =false;
/*if(value >100)limit = value/10; // if 1 number is not prime it will generate
if(value >10000)limit = value/100; //at lest 2 factor (not 1 or itself)
if(value >90000)limit = value/300; // 1 greater than average 1 lower than average
if(value >1000000)limit = value/1000; //ex: 9997 =13*769 (average ~ sqrt(9997) is 100)
if(value >4000000)limit = value/2000; //so we just want to check divisor up to 100
if(value >9000000)limit = value/3000; // for prime ~10000
*/
limit = (int)Math.sqrt(value); //General case
for(n=2; n <= limit; n++){
if(value % n == 0 && value != 2){
isprime = false;
break;
}
}
return isprime;
}
import java.io.*;
import java.util.Scanner;
class Test{
public static void main(String args[]){
Test tt=new Test();
Scanner obj=new Scanner(System.in);
int m,n;
System.out.println(i);
m=obj.nextInt();
n=obj.nextInt();
tt.IsPrime(n,m);
}
public void IsPrime(int num,int k)
{
boolean[] isPrime = new boolean[num+1];
// initially assume all integers are prime
for (int i = 2; i <= num; i++) {
isPrime[i] = true;
}
// mark non-primes <= N using Sieve of Eratosthenes
for (int i = 2; i*i <= num; i++) {
// if i is prime, then mark multiples of i as nonprime
// suffices to consider mutiples i, i+1, ..., N/i
if (isPrime[i]) {
for (int j = i; i*j <=num; j++) {
isPrime[i*j] = false;
}
}
}
for (int i =k; i <= num; i++) {
if (isPrime[i])
{
System.out.println(i);
}
}
}
}
List<int> prime(int x, int y)
{
List<int> a = new List<int>();
int b = 0;
for (int m = x; m < y; m++)
{
for (int i = 2; i <= m / 2; i++)
{
b = 0;
if (m % i == 0)
{
b = 1;
break;
}
}
if (b == 0) a.Add(m)`
}
return a;
}

Categories

Resources