繁体   English   中英

将列表中的值分组到存储桶中以使值的总和保持在或低于阈值

[英]Grouping values from list into buckets to keep sum of values at or below threshold

我有一个以分钟为单位的时间列表,表示完成某项工作所需的时间,但在任何一天中,工作所花费的时间不能超过 240 分钟。我想分成 N 组,以便项目的总和在组中不超过阈值(本例中为 240)。

示例列表可以是[60, 70, 90, 120, 180, 240]

上述列表的一种可能解决方案是: [[240], [180, 60], [70, 90], [120]] 请注意每个列表中的每个总和如何不超过 240 的阈值,同时留下一些剩余部分很好,但我怎么知道这是最佳解决方案? 最优被定义为同时最小化剩余和桶的数量。

我一直在努力尝试用 Python 中的一些for循环来做到这一点,但它感觉效率尽可能低。 此外,由于从列表中删除项目的方法, for循环不会遍历所有值。 下面是我的尝试。

import random
import math

def roundup(x):
    return int(math.ceil(x / 10.0)) * 10

threshold = 240;

randomlist = []

for i in range(0,10):
    n = random.randint(30,240)
    randomlist.append(roundup(n))

days = []

print (randomlist)

for item in randomlist:
    schedule = []
    schedule.append(item)
    minutes_remaining = threshold - item
    for item2 in randomlist:
        if randomlist.index(item) != randomlist.index(item2):
            if item2 <= minutes_remaining:
                minutes_remaining -= item2
                schedule.append(item2)
                randomlist.remove(item2)
    randomlist.remove(item)
    days.append(schedule)

print (days)
from itertools import permutations, product, accumulate

THRESHOLD = 240


def make_groups(lst, n):
    """
    Make n groups. The sum of the items in the group does not exceed 
    the threshold.
    """
    groups = []
    grps_range = [range(1, len(lst) - n + 2) for _ in range(n)]
    combo = [i for i in product(*grps_range) if sum(i) == len(lst)]
    for c in combo:
        marker = [0] + list(accumulate(c))
        group = [tuple(sorted(lst[i:j])) for i, j in zip(marker, marker[1:])]
        conform = [sum(g) <= THRESHOLD for g in group]
        if all(conform):
            groups.append(tuple(sorted(group)))

    return groups


def ngroups_leftover(entry):
    """
    Returns number of groups and sum of left over times
    """
    ngroups = len(entry)
    leftover = [THRESHOLD - sum(x) for x in entry]
    return ngroups, sum(leftover)


groups = []
l = [60, 70, 90, 120, 180, 240]
perm = permutations(l)
for p in perm:
    for i in range(1, len(p) + 1):
        result = make_groups(p, i)
        groups += result

unique_groups = set(groups)

x = sorted(unique_groups, key=ngroups_leftover)
# There are many solutions which result in the same number of groups
# and left over time. But, the first entry would do.
print(x[0])

Output

((60, 180), (70,), (90, 120), (240,))

所有可能的组合:

[((60, 180), (70,), (90, 120), (240,)),
 ((60, 70), (90, 120), (180,), (240,)),
 ((60, 180), (70, 120), (90,), (240,)),
 ((60, 90), (70, 120), (180,), (240,)),
 ((60, 120), (70, 90), (180,), (240,)),
 ((60, 70, 90), (120,), (180,), (240,)),
 ((60, 180), (70, 90), (120,), (240,)),
 ((60, 180), (70,), (90,), (120,), (240,)),
 ((60,), (70, 90), (120,), (180,), (240,)),
 ((60, 70), (90,), (120,), (180,), (240,)),
 ((60,), (70, 120), (90,), (180,), (240,)),
 ((60, 120), (70,), (90,), (180,), (240,)),
 ((60, 90), (70,), (120,), (180,), (240,)),
 ((60,), (70,), (90, 120), (180,), (240,)),
 ((60,), (70,), (90,), (120,), (180,), (240,))]
from itertools import permutations 

l =[60, 70, 90, 120, 180, 240]

perm = permutations(l)

results = []
for p in perm:

    for i in range(1, len(p)):
        if sum(p[ : i]) <= 240:    
            results += [ tuple( sorted( p[ : i] ) ) ]

print(list(set(results)))

打印输出是:

[(90,), (90, 120), (60, 70, 90), (180,), (60,), (120,), (60, 180), (240,), (70,), (70, 120), (60, 90), (70, 90), (60, 70), (60, 120)]

我尝试了一个贪婪的解决方案O( N log(N) + N) ,不确定它是否是最优的。

inp = [60, 70, 90, 120, 180, 240]
inp.sort()

i =0
j = len(inp)-1
k = 240
while j >= i:
    tmp = []
    tmp.append(inp[j])
    sm = inp[j]
    while i < j:
        if sm + inp[i] > k:
            break
        sm += inp[i]
        tmp.append(inp[i])
        i+=1
    print(tmp)
    j-=1

Output:

[240]
[180, 60]
[120, 70]
[90]

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM