Python 将列表拆分为平衡权重的块
我需要一个算法来将一个值列表分割成这样的块,每个块中的值之和(约为)等于(我想是它的一些变化) 例如[1,2,1,4,10,3,8]=>[8,2],[10],[1,3,1,4]] 长度相等的块是首选,但这不是一个约束 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.创建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