Lak*_*sad 23 python algorithm np-complete knapsack-problem dynamic-programming
有一个数字列表.
该列表将分为2个相等大小的列表,总和之间的差异最小.必须打印总和.
#Example:
>>>que = [2,3,10,5,8,9,7,3,5,2]
>>>make_teams(que)
27 27
Run Code Online (Sandbox Code Playgroud)
在某些情况下,以下代码算法是否存在错误?
我如何优化和/或pythonize这个?
def make_teams(que):
que.sort()
if len(que)%2: que.insert(0,0)
t1,t2 = [],[]
while que:
val = (que.pop(), que.pop())
if sum(t1)>sum(t2):
t2.append(val[0])
t1.append(val[1])
else:
t1.append(val[0])
t2.append(val[1])
print min(sum(t1),sum(t2)), max(sum(t1),sum(t2)), "\n"
Run Code Online (Sandbox Code Playgroud)
Geo*_*lly 29
动态编程是您正在寻找的解决方案.
[4,3,10,3,2,5]的示例:
X-Axis: Reachable sum of group. max = sum(all numbers) / 2 (rounded up)
Y-Axis: Count elements in group. max = count numbers / 2 (rounded up)
1 2 3 4 5 6 7 8 9 10 11 12 13 14
1 | | | | 4| | | | | | | | | | | // 4
2 | | | | | | | | | | | | | | |
3 | | | | | | | | | | | | | | |
1 2 3 4 5 6 7 8 9 10 11 12 13 14
1 | | | 3| 4| | | | | | | | | | | // 3
2 | | | | | | | 3| | | | | | | |
3 | | | | | | | | | | | | | | |
1 2 3 4 5 6 7 8 9 10 11 12 13 14
1 | | | 3| 4| | | | | |10| | | | | // 10
2 | | | | | | | 3| | | | | |10|10|
3 | | | | | | | | | | | | | | |
1 2 3 4 5 6 7 8 9 10 11 12 13 14
1 | | | 3| 4| | | | | |10| | | | | // 3
2 | | | | | | 3| 3| | | | | |10|10|
3 | | | | | | | | | | 3| | | | |
1 2 3 4 5 6 7 8 9 10 11 12 13 14
1 | | 2| 3| 4| | | | | |10| | | | | // 2
2 | | | | | 2| 3| 3| | | | | 2|10|10|
3 | | | | | | | | 2| 2| 3| | | | |
1 2 3 4 5 6 7 8 9 10 11 12 13 14
1 | | 2| 3| 4| 5| | | | |10| | | | | // 5
2 | | | | | 2| 3| 3| 5| 5| | | 2|10|10|
3 | | | | | | | | 2| 2| 3| 5| 5| | |
^
12是我们的幸运数字!回溯以获得该组:
12 - 5 = 7 {5}
7 - 3 = 4 {5, 3}
4 - 4 = 0 {5, 3, 4}
然后可以计算另一组:{4,3,10,3,2,5} - {5,3,4} = {10,3,2}
带有数字的所有字段都是一个包的可能解决方案.选择右下角最远的那个.
BTW:它被称为背包问题.
如果所有权重(w1,...,wn和W)都是非负整数,则可以使用动态编程在伪多项式时间内解决背包问题.
新解决方案
这是一种利用启发式剔除的广度优先搜索.树被限制在玩家的深度/ 2.玩家总和限额为totalscores/2.玩家池数为100,需要大约10秒才能解决.
def team(t):
iterations = range(2, len(t)/2+1)
totalscore = sum(t)
halftotalscore = totalscore/2.0
oldmoves = {}
for p in t:
people_left = t[:]
people_left.remove(p)
oldmoves[p] = people_left
if iterations == []:
solution = min(map(lambda i: (abs(float(i)-halftotalscore), i), oldmoves.keys()))
return (solution[1], sum(oldmoves[solution[1]]), oldmoves[solution[1]])
for n in iterations:
newmoves = {}
for total, roster in oldmoves.iteritems():
for p in roster:
people_left = roster[:]
people_left.remove(p)
newtotal = total+p
if newtotal > halftotalscore: continue
newmoves[newtotal] = people_left
oldmoves = newmoves
solution = min(map(lambda i: (abs(float(i)-halftotalscore), i), oldmoves.keys()))
return (solution[1], sum(oldmoves[solution[1]]), oldmoves[solution[1]])
print team([90,200,100])
print team([2,3,10,5,8,9,7,3,5,2])
print team([1,1,1,1,1,1,1,1,1,9])
print team([87,100,28,67,68,41,67,1])
print team([1, 1, 50, 50, 50, 1000])
#output
#(200, 190, [90, 100])
#(27, 27, [3, 9, 7, 3, 5])
#(5, 13, [1, 1, 1, 1, 9])
#(229, 230, [28, 67, 68, 67])
#(150, 1002, [1, 1, 1000])
Run Code Online (Sandbox Code Playgroud)
另请注意,我尝试使用GS的描述解决此问题,但仅通过存储运行总计来获取足够的信息是不可能的.如果您同时存储了项目数和总数,那么它将与此解决方案相同,除非您保留了不必要的数据.因为您只需要将n-1和n次迭代保持为numplayers/2.
我有一个基于二项式系数的旧的详尽的(在历史中看).它解决了长度为10的示例性问题,但后来我看到竞争对手的人数达到了100.