Вопрос: Создайте серию случайных чисел, которые добавляют до N в c #


Как я могу генерировать 30 случайных чисел между 1-9, чтобы все добавляли до 200 (или некоторых произвольных N) в C #?

Я пытаюсь сгенерировать строку цифр, которые могут быть объединены, чтобы быть N.


12


источник


Ответы:


Я не уверен, что такое статистика, но проблема заключается в том, что вы не хотите случайным образом выбирать число, которое делает невозможным суммирование N с M количеством записей либо путем превышения или недогрузки. Вот как я это сделаю:

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;
}

У меня не было много времени, чтобы проверить это, так что извини, если есть какая-то ошибка в моей логике.

РЕДАКТИРОВАТЬ:

Я сделал несколько тестов, и все кажется твердым. Если вы хотите красивого распространения, похоже, что вы хотите что-то вроде Total = Count * ((UPPER + LOWER) / 2), Хотя я вполне уверен, что, поскольку разница между UPPER а также LOWER это становится более гибким.


8



Проблема в том, что мы хотим, чтобы все числа были ограничены 1-9 а также  добавить к N. Таким образом, мы должны генерировать каждое число один за другим и определять реальные оценки для следующего числа.

Это, конечно, приведет к статистическому смещению к концу списка, поэтому я рекомендую перетасовывать массив один раз после генерации.

Чтобы определить границы следующего номера, сделайте следующее: Верхняя граница = возьмите оставшуюся сумму минус (количество оставшихся элементов * min). Нижняя граница = взять оставшуюся сумму минус (количество оставшихся элементов * max).

Что-то вроде (непроверено):

public static List<int> RandomList(int digitMin, int digitMax, 
                                   int targetSum, int numDigits)
{
    List<int> ret = new List<int>(numDigits);

    Random random = new Random();
    int localMin, localMax, nextDigit;
    int remainingSum = targetSum;

    for(int i=1; i<=numDigits; i++)
    {
          localMax = remainingSum - ((numDigits - i) * min);
          if(localMax > max)
              localMax = max;

          localMin = remainingSum - ((length - i) * max);
          if(localMin > min)
              localMin = min;

          nextDigit = random.Next(localMin, localMax);
          ret.Add(nextDigit);
          remainingSum -= nextDigit;
    }

    return ret;
}

Идея здесь заключается в том, что вы генерируете числа, диапазон возможных значений для остальных чисел становится меньше, например, предельная функция, обнуляющая в целевой сумме. Вроде.

Изменить: мне пришлось изменить цикл for на 1-й, потому что мы хотим, чтобы число элементов осталось после генерации этого.

Edit2: Поместите его в метод для полноты и измените length быть numDigits для удобочитаемости.


7



Мое оригинальное заявление:

Вы можете генерировать только 29 случайных чисел. 30-е число будет определяться другими 29 и суммой. Это статистически важно ...

Я хотел добавить некоторые разъяснения, подумав об этом и пинг  общество...

Теперь я считаю, что мое первоначальное утверждение ложно. Это было слишком снисходительно (на что указал lc). Вы даже не можете генерировать 29 по-настоящему случайных чисел. По мере приближения и приближения к 30 конечные цифры не являются случайными, так как rnd [1..9] является случайным. lc попытался смягчить это, чтобы придумать решение, но я считаю, что решение, которое он придумал (и Спенсер), отвечает на совсем другой вопрос. Этот вопрос: «Из всех наборов из 30 цифр от 1 до 9, которые составляют до 200, постройте один случайным образом».

Я считаю, что это так, так как вопрос, который был сформулирован, неразрешимый, который, я считаю, можно доказать с помощью Принцип Pigeonhole  (также используемый Кнутом, чтобы показать, что некоторые «случайные» перетасовки не были действительно случайными), но я не сделал математику.

Хороший разговор всех.


4



Эта программа попытается дать вам ответ. Но поскольку вы имеете дело со случайными числами, есть вероятность, что это никогда не даст вам ответа.

public static IEnumerable<int> GetRandom()
{
    var rand = new Random();
    while (true)
    {
        yield return
        rand.Next(1, 9);
    }
}

public static List<int> GetThirtyThatAddToTwoHundred()
{
    do
    {
        var current = GetRandom().Take(30);
        if (200 == current.Sum())
        {
            return current.ToList();
        }
    } while (true);
}

3



После всех обсуждений здесь есть еще один способ создать список, который не вводит предвзятость. Да, он отличается от того, что задает вопрос, но вместо случайного выбора цифр вы можете произвольно увеличивать цифры до тех пор, пока не достигнете суммы. Как и следующие (опять же непроверенные):

public static List<int> RandomListByIncrementing(int digitMin, int digitMax, 
                                                 int targetSum, int numDigits)
{
    if(targetSum < digitMin * numDigits || targetSum > digitMax * numDigits)
        throw new ArgumentException("Impossible!", "targetSum");

    List<int> ret = new List<int>(Enumerable.Repeat(digitMin, numDigits));
    List<int> indexList = new List<int>(Enumerable.Range(0, numDigits-1));

    Random random = new Random();
    int index;

    for(int currentSum=numDigits * digitMin; currentSum<targetSum; currentSum++)
    {
        //choose a random digit in the list to increase by 1
        index = random.Next(0,indexList.Length-1);

        if(++ret[indexList[index]] == digitMax)
        {
            //if you've increased it up to the max, remove its reference
            //because you can't increase it anymore
            indexList.RemoveAt(index);
        }
    }

    return ret;
}

Идея здесь заключается в том, что вы сохраняете список ссылок на ваш список номеров. Выберите произвольную ссылку и увеличьте соответствующее число. Если вы больше не можете увеличивать его, удалите ссылку, чтобы вы не выбирали ее в следующий раз.

Теперь в конце дня нет никакого перетасовки, хотя, возможно, это все равно произведет один из доступных наборов ответов на вопрос, и это вопрос о том, какой из них «чувствует себя лучше» или работает быстрее.


1



Поэтому я должен спросить: Есть ли реальная цель для этого, или это просто упражнение или домашнее задание? Проводится большая работа по предотвращению «предвзятости». Является ли это реальным требованием или будет какое-либо довольно случайное решение? Не зная требований, очень легко тратить много времени. Если это реальная проблема, пожалуйста, объясните, каковы фактические требования.


1



Если допустимо статистическое отклонение от истинной случайности, вы можете добавить числа до N - [максимальное случайное число], а затем выбрать последнее число как N - сумму (выбранную до сих пор).


0



Алгоритм:

  1. Set total = 200 (или что-то еще)
  2. Генерировать случайное число между 1-9
  3. Проверьте, если (total - newRandomNumber> = 0), если нет goto 6
  4. total - = newRandomNumber
  5. Добавить newRandomNumber в массив, goto 2.
  6. newRandomNumber = total
  7. Добавить newRandomNumber в массив, если newRandomNumber! = 0
  8. Конец

0



Нет никакого guarrentee, что 30 случайных чисел от 1-9 добавили бы к любому конкретному N.

Вы можете найти список чисел, которые будут содержать до N и ограничены от 1 до 9, но число не будет равно 30. Я считаю, что минимальное количество нужных вам чисел равно 23, будучи (22 * 9) + 2. Максимум, конечно, будет 200 (200 * 1). Таким образом, длина списка находится где-то внутри [23,200]. Таким образом, вероятность того, что случайный список может быть длиной 30, является довольно низкой. Если все длины списков доступны (я думаю, что они), ваши шансы в долгосрочной перспективе составляют около 0,5%.


0