Как я генерирую универсальный случайный целочисленный раздел?

Поиск Google показывает много о генерации всех возможных разделов целого числа n в m части, но я ничего не нашел о выборке равномерно распределенного случайного раздела n в m части.

19
задан Bill the Lizard 29 January 2010 в 15:01
поделиться

3 ответа

Вот код, который это делает. Это O(n2) при первом вызове, но он строит кэш так, чтобы последующие вызовы были O(n).

import random

cache = {}

def count_partitions(n, limit):
    if n == 0:
        return 1
    if (n, limit) in cache:
        return cache[n, limit]
    x = cache[n, limit] = sum(count_partitions(n-k, k) for k in range(1, min(limit, n) + 1))
    return x

def random_partition(n):
    a = []
    limit = n
    total = count_partitions(n, limit)
    which = random.randrange(total)
    while n:
        for k in range(1, min(limit, n) + 1):
            count = count_partitions(n-k, k)
            if which < count:
                break
            which -= count
        a.append(k)
        limit = k
        n -= k
    return a

Как это работает: Мы можем вычислить, сколько разделов целого n находится во времени O(n2). В качестве побочного эффекта получается таблица размера O(n2), которую мы можем использовать для создания kth раздела n, для любого целого k, во времени O(n).

Пусть насчитывает = количество разделов. Выберите случайное число k от 0 до итого - 1. Сгенерируйте k раздел.

10
ответ дан 30 November 2019 в 04:24
поделиться

После некоторого поиска в Google я нашел алгоритм для этого в «Руководстве по прикладным алгоритмам» , который Google Книги проиндексировал . Алгоритм приведен в разделе 1.12.2 на странице 31.

0
ответ дан 30 November 2019 в 04:24
поделиться

Еще одна версия на C #.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace ConsoleApplication6
{
    class Program
    {
        static Random random = new Random();

        static void Main(string[] args)
        {
            PrintPartition(GetUniformPartition(24, 5));
            PrintPartition(GetUniformPartition(24, 5));
            PrintPartition(GetUniformPartition(24, 5));
            PrintPartition(GetUniformPartition(24, 5));
            PrintPartition(GetUniformPartition(24, 5));
            Console.ReadKey();
        }

        static int[] GetUniformPartition(int input, int parts)
        {
            if(input<= 0 || parts <= 0)
                throw new ArgumentException("invalid input or parts");
            if (input < MinUniformPartition(parts))
                throw new ArgumentException("input is to small");

            int[] partition = new int[parts];
            int sum = 0;
            for (int i = 0; i < parts-1; i++)
            {
                int max = input - MinUniformPartition(parts - i - 1) - sum;
                partition[i] = random.Next(parts - i, max);
                sum += partition[i];
            }
            partition[parts - 1] = input - sum; // last 
            return partition;
        }

        // sum of 1,2,3,4,..,n
        static int MinUniformPartition(int n)
        {
            return n * n - 1;
        }

        static void PrintPartition(int[] p)
        {
            for (int i = 0; i < p.Length; i++)
            {
                Console.Write("{0},", p[i]);
            }
            Console.WriteLine();
        }
    }
}

Этот код выдаст следующий результат:

5,8,7,2,2,
6,6,7,2,3,
5,7,6,2,4,
6,4,3,2,9,
7,8,4,4,1,
1
ответ дан 30 November 2019 в 04:24
поделиться
Другие вопросы по тегам:

Похожие вопросы: