Python 将列表拆分为平衡权重的块

Python 将列表拆分为平衡权重的块,python,algorithm,optimization,language-agnostic,combinatorics,Python,Algorithm,Optimization,Language Agnostic,Combinatorics,我需要一个算法来将一个值列表分割成这样的块,每个块中的值之和(约为)等于(我想是它的一些变化) 例如[1,2,1,4,10,3,8]=>[8,2],[10],[1,3,1,4]] 长度相等的块是首选,但这不是一个约束 Python是首选语言,但也欢迎其他语言 编辑:定义了块的数量贪婪: 1.按降序排列可用项目。 2.创建N个空组 3.开始将项目一次添加到总和最小的组中 我认为在大多数现实生活中,这应该足够了。你可能需要使用人工智能工具来解决这个问题。 首先定义你的问题 States={(c1,c

我需要一个算法来将一个值列表分割成这样的块,每个块中的值之和(约为)等于(我想是它的一些变化)

例如[1,2,1,4,10,3,8]=>[8,2],[10],[1,3,1,4]]

长度相等的块是首选,但这不是一个约束

Python是首选语言,但也欢迎其他语言


编辑:定义了块的数量

贪婪:
1.按降序排列可用项目。
2.创建N个空组
3.开始将项目一次添加到总和最小的组中


我认为在大多数现实生活中,这应该足够了。

你可能需要使用人工智能工具来解决这个问题。 首先定义你的问题

States={(c1,c2,...,ck) | c1,...,ck are subgroups of your problem , and union(c1,..,ck)=S } 
successors((c1,...,ck)) = {switch one element from one sub list to another } 
utility(c1,...,ck) = max{sum(c1),sum(c2)...} - min{sum(c1),sum(c2),...}
现在,您可以使用随机重新启动


这个算法将是,这意味着你可以开始搜索,当时间到了,停止它,你将得到迄今为止最好的结果。随着运行时间的增加,结果会更好。

基于@Alin Purcaru answer和@amit注释,我编写了代码(Python 3.1)。据我所测试的,它的性能是线性的(项目数和块数都是线性的,所以最后是O(N*M))。我避免每次都对列表进行排序,在dict中保留每个块的当前值总和(如果块的数量较多,则不太实用)

只是因为,你知道,我们可以在PHP5.3中使用相同的代码(比Python 3.1慢2-3倍):

函数分割块($l,$n){
$result=array_fill(0,$n,array());
$sums=数组填充(0,$n,0);
$c=0;
foreach($l为$e){
foreach($i=>$sum){
如果($c==$sum){
$result[$i][]=$e;
打破
}//如果
}//foreach
$sums[$i]+=$e;
$c=最小值(总和);
}//foreach
返回$result;
}
定义(“最小值”,0);
定义(“最大值”,20000000);
定义(“项目”,50000);
定义('CHUNKS',128);
$l=数组();

对于($i=0;$i这将更快更干净(基于上述想法!)


我担心你的问题没有很好的定义。是否需要块的数量与完全相等和的偏差?目前提出的这个问题有一个简单的解决方案,只有一个块。它有NP难的味道。你应该定义什么是“近似”,因为我相信没有多项式解可以找到最佳分割。@Petar Ivanov:我在编辑中进行了精确计算-块的数量是defined@amit:这就是为什么我要寻找近似值这是广义的划分问题:,它是NP完全的。O(NlogN)排序是瓶颈,这个解决方案将确保两个组之间的差异在不同的线程中最多是max{S},与此类似,我已经证明max{S}-min{S}是这个算法的最大差异。看看:@amit。将
[1,1,1]
拆分为两个块怎么样?我认为max(S)听起来更像是正确的答案。在另一个线程中,类似于这个线程,我已经证明了max{S}-min{S}是这个算法的最大差异。看看:假设没有提供任何解释,一些标识符可能更能说明问题。
import time, random

def split_chunks(l, n):
    """ 
       Splits list l into n chunks with approximately equals sum of values
       see  http://stackoverflow.com/questions/6855394/splitting-list-in-chunks-of-balanced-weight
    """
    result = [[] for i in range(n)]
    sums   = {i:0 for i in range(n)}
    c = 0
    for e in l:
        for i in sums:
            if c == sums[i]:
                result[i].append(e)
                break
        sums[i] += e
        c = min(sums.values())    
    return result


if __name__ == '__main__':

    MIN_VALUE = 0
    MAX_VALUE = 20000000
    ITEMS     = 50000
    CHUNKS    = 256

    l =[random.randint(MIN_VALUE, MAX_VALUE ) for i in range(ITEMS)]

    t = time.time()

    r = split_chunks(l, CHUNKS)

    print(ITEMS, CHUNKS, time.time() - t)
function split_chunks($l, $n){

    $result = array_fill(0, $n, array());
    $sums   = array_fill(0, $n, 0);
    $c = 0;
    foreach ($l as $e){
        foreach ($sums as $i=>$sum){
            if ($c == $sum){
                $result[$i][] = $e;
                break;  
            } // if
        } // foreach
        $sums[$i] += $e;        
        $c = min($sums);
    } // foreach
    return $result;
}

define('MIN_VALUE',0);
define('MAX_VALUE',20000000);
define('ITEMS',50000);
define('CHUNKS',128);

$l = array();
for ($i=0; $i<ITEMS; $i++){
    $l[] = rand(MIN_VALUE, MAX_VALUE);  
}

$t = microtime(true);

$r = split_chunks($l, CHUNKS);

$t = microtime(true) - $t;

print(ITEMS. ' ' .  CHUNKS .' ' . $t . ' ');
def split_chunks2(l, n):
    result = [[] for i in range(n)]
    sums   = [0]*n
    i = 0
    for e in l:
        result[i].append(e)
        sums[i] += e
        i = sums.index(min(sums)) 
    return result