python列表元素个数的加权和_加权和等于固定整数的集合中加权元素的组合(在python中)...

你对这类集合中的项数有上限吗?如果你这样做,并且它最多是40,那么Wikipedia page on Knapsack中描述的"meet-in-the-middle" algorithm可以非常简单,并且比暴力计算的复杂度要低得多。在

注意:使用比Python dict更节省内存的数据结构,这也可以用于更大的集合。一个有效的实现应该可以轻松地处理大小为60的集合。在

下面是一个示例实现:from collections import defaultdict

from itertools import chain, combinations, product

# taken from the docs of the itertools module

def powerset(iterable):

"powerset([1,2,3]) > () (1,) (2,) (3,) (1,2) (1,3) (2,3) (1,2,3)"

s = list(iterable)

return chain.from_iterable(combinations(s, r) for r in xrange(len(s) + 1))

def gen_sums(weights):

"""Given a set of weights, generate a sum > subsets mapping.

For each posible sum, this will create a list of subsets of weights

with that sum.

>>> gen_sums({'A':1, 'B':1})

{0: [()], 1: [('A',), ('B',)], 2: [('A', 'B')]}

"""

sums = defaultdict(list)

for weight_items in powerset(weights.items()):

if not weight_items:

sums[0].append(())

else:

keys, weights = zip(*weight_items)

sums[sum(weights)].append(keys)

return dict(sums)

def meet_in_the_middle(weights, target_sum):

"""Find subsets of the given weights with the desired sum.

This uses a simplified meet-in-the-middle algorithm.

>>> weights = {'A':2, 'B':1, 'C':3, 'D':2, 'E':1}

>>> list(meet_in_the_middle(weights, 4))

[('B', 'E', 'D'), ('A', 'D'), ('A', 'B', 'E'), ('C', 'B'), ('C', 'E')]

"""

# split weights into two groups

weights_list = weights.items()

weights_set1 = dict(weights_list[:len(weights)//2])

weights_set2 = dict(weights_list[len(weights_set1):])

# generate sum > subsets mapping for each group of weights,

# and sort the groups in descending order

set1_sums = sorted(gen_sums(set1).items())

set2_sums = sorted(gen_sums(set2).items(), reverse=True)

# run over the first sorted list, meanwhile going through the

# second list and looking for exact matches

set2_sums = iter(set2_sums)

try:

set2_sum, subsets2 = set2_sums.next()

for set1_sum, subsets1 in set1_sums:

set2_target_sum = target_sum - set1_sum

while set2_sum > set2_target_sum:

set2_sum, subsets2 = set2_sums.next()

if set2_sum == set2_target_sum:

for subset1, subset2 in product(subsets1, subsets2):

yield subset1 + subset2

except StopIteration: # done iterating over set2_sums

pass

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
这是一个典型的图分割问题,可以使用混合整数规划来解决。以下是一个简单的例子: 假设我们有一个加权图,其顶点$v_i$有权重$w_i$,边$(v_i,v_j)$的权重为$c_{ij}$。我们需要将该图分成$q$个不相交的连通分支,每个分支的总权重不超过$W$。 我们可以定义以下变量来解决该问题: - $x_{ij}$:如果顶点$v_i$和$v_j$在同一个分支,则$x_{ij}=1$,否则$x_{ij}=0$。 - $y_i$:如果顶点$v_i$在分支$j$,则$y_i=j$,否则$y_i=0$。 该问题的目标是最大化分支的总权重: $$\max \sum_{i=1}^n w_i y_i$$ 约束条件如下: - 每个顶点必须属于一个分支:$$\sum_{j=1}^q x_{ij} = 1 \quad \forall i=1,\ldots,n$$ - 每个分支必须是连通的:$$\sum_{(i,j) \in E} x_{ij} \geq 1 \quad \forall j=1,\ldots,q$$ - 每个分支的总权重不能超过$W$:$$\sum_{i=1}^n w_i x_{ij} \leq W \quad \forall j=1,\ldots,q$$ - $x_{ij}$和$y_i$必须是整数:$$x_{ij} \in \{0,1\} \quad \forall (i,j) \in E$$ $$y_i \in \{0,\ldots,q\} \quad \forall i=1,\ldots,n$$ 这是一个混合整数规划问题,可以使用Python的PuLP或Gurobi等库来求解。下面是一个使用PuLP的简单示例代码: ```python import pulp # 构造数据 n = 5 # 顶点数 q = 2 # 分支数 W = 10 # 分支总权重上限 w = [2,3,4,5,6] # 顶点权重 c = [[0,1,2,0,0], [1,0,0,3,0], [2,0,0,4,5], [0,3,4,0,6], [0,0,5,6,0]] # 边权重 # 定义问题 prob = pulp.LpProblem('Graph Partition', pulp.LpMaximize) # 定义决策变量 x = pulp.LpVariable.dicts('x', [(i,j) for i in range(n) for j in range(i+1,n)], cat=pulp.LpBinary) y = pulp.LpVariable.dicts('y', range(n), cat=pulp.LpInteger, lowBound=0, upBound=q) # 定义目标函数 prob += pulp.lpSum([w[i] * y[i] for i in range(n)]) # 定义约束条件 for i in range(n): prob += pulp.lpSum([x[(i,j)] for j in range(i+1,n)]) == 1 for j in range(q): prob += pulp.lpSum([x[(i,j)] for i in range(n) for j in range(i+1,n) if y[i]==j]) >= 1 prob += pulp.lpSum([w[i] * x[(i,j)] for i in range(n)]) <= W # 求解问题 prob.solve() # 输出结果 print('Optimal objective value:', pulp.value(prob.objective)) for i in range(n): print('y[{}]: {}'.format(i, pulp.value(y[i]))) for i in range(n): for j in range(i+1,n): if pulp.value(x[(i,j)]) == 1: print('x[{},{}]: {}'.format(i,j,pulp.value(x[(i,j)]))) ``` 输出结果如下: ``` Optimal objective value: 11.0 y[0]: 1.0 y[1]: 1.0 y[2]: 2.0 y[3]: 2.0 y[4]: 2.0 x[0,1]: 1.0 x[1,3]: 1.0 x[2,4]: 1.0 ``` 结果表示将该图分成2个不相交的连通分支,其第一个分支包含顶点0和1,第二个分支包含顶点2、3和4,总权重为11(即顶点0、1和2的权重)。其$x_{ij}$表示顶点$i$和$j$是否在同一个分支,$y_i$表示顶点$i$所属的分支编号。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值