如何将数字分成多个部分(不相等),以使总和等于输入?

时间:2018-11-02 07:21:36

标签: algorithm

我想除数例如从一个范围内随机选择的不同令牌(30个部分)中输入数字40,该数字必须等于输入数字40。 编辑: 最大范围应为40%,最小值应为0。

示例:

range = (0,4)

1+1+0+1+1+0+3+0+3+0+0+2+0+4+4+1+1+0+1+1+0+3+0+4+0+2+2+0+4+1 = 40.

实际上是在现实世界中显示方案的结果我需要一个产品用户表达式的总和,我需要将它们随机填充到上个月每一天的记录集中。我正在使用php,但无法获取算法来处理这种情况。

2 个答案:

答案 0 :(得分:2)

简单方法利用“尝试和错误”方法。适用于合理的小输入值。

注意-当n接近p*maxx时,它可能会长时间工作。如果可能的话,分配“漏洞”而不是“一个”(第二种代码)会更明智

import random

def randparts(n, p, maxx):
    lst = [0] * p
    while n > 0:
        r = random.randrange(p)
        if lst[r] < maxx:
            n -= 1
            lst[r] += 1
    return lst

print(randparts(20, 10, 4))

>>>  [2, 0, 3, 2, 4, 2, 1, 3, 0, 3]

def randparts(n, p, maxx):
    if p * maxx  >=  n * 2:
        lst = [0] * p
        while n > 0:
            r = random.randrange(p)
            if lst[r] < maxx:
                n -= 1
                lst[r] += 1
    else:
        lst = [maxx] * p
        n = maxx * p - n
        while n > 0:
            r = random.randrange(p)
            if lst[r] > 0:
                n -= 1
                lst[r] -= 1
    return lst

print(randparts(16, 10, 4))
print(randparts(32, 10, 4))

>> [2, 0, 0, 3, 4, 0, 0, 3, 2, 2]
>> [3, 4, 4, 4, 4, 0, 3, 3, 4, 3]

答案 1 :(得分:0)

由于您提到的是“上个月每天的记录集”,因此我假设令牌的数量也可以是28或31,并且由于您说的是“随机”,因此我将这样做做

1. create a function that takes in:
    a. The number to sum to (40 in your example).
    b. The maximum number of a single token (4 in your example).
    c. The number of tokens (30 in your example).
2. Within the function, create an array the size of the number of tokens (28, 30, 31, or whatever)
3. Initialize all elements of the array to zero.
4. Check to make sure that it is possible to achieve the sum given the maximum single token value and number of tokens.
5. While I need to increment a token (sum > 0):
    a. Select a random token.
    b. Determine if the value of the token can be incremented without going over the max single token value.
    c. If it can, then increment the token value and decrement the sum.
    d. If the token cannot be incremented, then go back to 5a.
6. Return the array of tokens, or however you want them back (you didn't specify).

以下是c#中的示例:

public int[] SegmentSum(int sum, int maxPart, int parts)
{
    if (sum < 0 || maxPart < 0 || parts < 0 || parts * maxPart < sum)
        throw new ArgumentOutOfRangeException;

    Random rnd = new Random();
    int[] tokens = Enumerable.Repeat(0, parts).ToArray();

    while(sum > 0)
    {
        int token = rnd.Next(parts);
        if (tokens[token] < maxPart)
        {
            tokens[token]++;
            sum--;
        }
    }
    return tokens;
}

希望这对您有所帮助。