Generate a series of random numbers that add up to N in c#

后端 未结 16 719

How do I generate 30 random numbers between 1-9, that all add up to 200 (or some arbitrary N), in C#?

I\'m trying to generate a string of digits that can add togethe

相关标签:
16条回答
  • 2020-12-15 22:47

    So I have to ask: Is there an actual purpose for this, or is it just an exercise or homework assignment? There is a lot of work going on to prevent "bias". Is this an actual requirement, or will any fairly random solution do? Without knowing the requirements it's really easy to waste a lot of time. If this is a real problem, please explain what the actual requirements are.

    0 讨论(0)
  • 2020-12-15 22:47

    If you want an unbiased algorithm then the naive implementation is something like:

    while (true) {
      numbers = [];
      total = 0;
      for (i = 0; i < COUNT; ++i) {
        next = rand(BOUNDS);
        total += next;
        numbers.push(next);
      }
    
      if (total == TARGET) {
        return numbers;
      }
    }
    

    This is non-terminating and slow but it is not biased. If you want a unbiased algorithm I'm not convinced the algorithms posted here are unbiased.

    0 讨论(0)
  • 2020-12-15 22:48

    There is no guarrentee that 30 random numbers from 1-9 would add up to any specific N.

    What you can find is a list of numbers which will add up to N and are bounded from 1-9 but the number will not be 30 necessarily. I believe the minimum number of numbers you need is 23, being (22*9) + 2. The maximum of course will be 200 (200*1). So the length of the list is somewhere inside [23,200]. The chances that a random list may be length 30 is thus quite low. If all list lengths are obtainable (i think they are) your chances in the long run at about 0.5%.

    0 讨论(0)
  • 2020-12-15 22:49

    I'm not sure what the statistics are on this but, the issue here is that you don't want to randomly select a number that makes it impossible to sum N with M number of entries either by overshooting or undershooting. Here's how I would do it:

    static void Main()
    {
        int count = 30;
        int[] numbers = getNumbers(count, 155);
        for (int index = 0; index < count; index++)
        {
            Console.Write(numbers[index]);
            if ((index + 1) % 10 == 0)
                Console.WriteLine("");
            else if (index != count - 1)
                Console.Write(",");
        }
        Console.ReadKey();
    }
    static int[] getNumbers(int count, int total)
    {
        const int LOWERBOUND = 1;
        const int UPPERBOUND = 9;
    
        int[] result = new int[count];
        int currentsum = 0;
        int low, high, calc;
    
        if((UPPERBOUND * count) < total ||
            (LOWERBOUND * count) > total ||
            UPPERBOUND < LOWERBOUND)
            throw new Exception("Not possible.");
    
        Random rnd = new Random();
    
        for (int index = 0; index < count; index++)
        {
            calc = (total - currentsum) - (UPPERBOUND * (count - 1 - index));
            low = calc < LOWERBOUND ? LOWERBOUND : calc;
            calc = (total - currentsum) - (LOWERBOUND * (count - 1 - index));
            high = calc > UPPERBOUND ? UPPERBOUND : calc;
    
            result[index] = rnd.Next(low, high + 1);
    
            currentsum += result[index];
        }
    
        // The tail numbers will tend to drift higher or lower so we should shuffle to compensate somewhat.
    
        int shuffleCount = rnd.Next(count * 5, count * 10);
        while (shuffleCount-- > 0)
            swap(ref result[rnd.Next(0, count)], ref result[rnd.Next(0, count)]);
    
        return result;
    }
    public static void swap(ref int item1, ref int item2)
    {
        int temp = item1;
        item1 = item2;
        item2 = temp;
    }
    

    I didn't have a lot of time to test this so apologies if there's a flaw in my logic somewhere.

    EDIT:

    I did some testing and everything seems solid. If you want a nice pretty spread it looks like you want something along the lines of Total = Count * ((UPPER + LOWER) / 2). Although I'm fairly certain that as the difference between UPPER and LOWER increases the more flexible this becomes.

    0 讨论(0)
提交回复
热议问题