### 将数字列表分成2个相等的总和列表的算法

``````#Example:
>>>que = [2,3,10,5,8,9,7,3,5,2]
>>>make_teams(que)
27 27
``````

``````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"
``````

#### 14 个答案:

Dynamic programming是您正在寻找的解决方案。

[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}
```

BTW：它被称为knapsack-problem

``````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])
``````

Q值。给定多整数S的整数，有没有办法将S分为两个子集 S1和S2，以便 S1中数字的总和等于S2中数字的总和？

NP完全，使用伪多项式dp算法。伪伪多项式是指运行时间取决于权重范围的事实。

PS此代码始终在时间限制内执行，但优化后。我保持简单直到它通过测试，然后我有一些想法加快它，可能是10倍或更多。

```#include <stdio.h>

#define TRUE (0==0)
#define FALSE (0!=0)

static int debug = TRUE;

//int simple(const void *a, const void *b) {
//  return *(int *)a - *(int *)b;
//}

int main(int argc, char **argv) {
int p[101];
char *s, line[128];
int skill, players, target, i, j, tests, total = 0;

debug = (argc == 2 && argv[1][0] == '-' && argv[1][1] == 'd' && argv[1][2] == '\0');

s = fgets(line, 127, stdin);
tests = atoi(s);
while (tests --> 0) {

for (i = 0; i < 45001; i++) {c0[i] = 0LL;}

s = fgets(line, 127, stdin); /* blank line */
s = fgets(line, 127, stdin); /* no of players */
players = atoi(s);
for (i = 0; i < players; i++) {s = fgets(line, 127, stdin); p[i] = atoi(s);}

if (players == 1) {
printf("0 %d\n", p[0]);
} else {

if (players&1) p[players++] = 0; // odd player fixed by adding a single player of 0 strength
//qsort(p, players, sizeof(int), simple);

total = 0; for ( i = 0; i < players; i++) total += p[i];
target = total/2; // ok if total was odd and result rounded down - teams of n, n+1
mask = 1LL << (((long long)players/2LL)-1LL);

for (i = 0; i < players; i++) {
for (j = 0; j <= target; j++) {c1[j] = 0LL;} // memset would be faster
skill = p[i];
//add this player to every other player and every partial subset
for (j = 0; j <= target-skill; j++) {
if (c0[j]) c1[j+skill] = c0[j]<<1;  // highest = highest j+skill for later optimising
}
c0[skill] |= 1; // so we don't add a skill number to itself unless it occurs more than once
for (j = 0; j <= target; j++) {c0[j] |= c1[j];}
if (c0[target]&mask) break; // early return for perfect fit!
}

for (i = target; i > 0; i--) {
if (debug || (c0[i] & mask)) {
fprintf(stdout, "%d %d\n", i, total-i);
if (debug) {
if (c0[i] & mask) printf("******** ["); else
printf("         [");
for (j = 0; j <= players; j++) if (c0[i] & (1LL<<(long long)j)) printf(" %d", j+1);
printf(" ]\n");
} else break;
}
}
}
if (tests) printf("\n");
}
return 0;
}
```

`````` def g(data):
sums = [0, 0]
for pair in zip(data[::2], data[1::2]):
item1, item2 = sorted(pair)
sums = sorted([sums[0] + item2, sums[1] + item1])
print sums

data = sorted([2,3,10,5,8,9,7,3,5,2])
g(data)
``````

``````que = [1, 1, 50, 50, 50, 1000]
``````

``````def make_teams(que):
que.sort()
que.reverse()
if len(que)%2: que.insert(0,0)
t1,t2 = [],[]
while que:
if abs(len(t1)-len(t2))>=len(que):
[t1, t2][len(t1)>len(t2)].append(que.pop(0))
else:
[t1, t2][sum(t1)>sum(t2)].append(que.pop(0))
print min(sum(t1),sum(t2)), max(sum(t1),sum(t2)), "\n"

if __name__=="__main__":
que = [2,3,10,5,8,9,7,3,5,2]
make_teams(que)
que = [1, 1, 50, 50, 50, 1000]
make_teams(que)
``````

``````def make_sequence():
"""return the sums and the sequence that's devided to make this sum"""
while 1:
seq_len = randint(5, 200)
seq_max = [5, 10, 100, 1000, 1000000][randint(0,4)]
seqs = [[], []]
for i in range(seq_len):
for j in (0, 1):
seqs[j].append(randint(1, seq_max))
diff = sum(seqs[0])-sum(seqs[1])
if abs(diff)>=seq_max:
continue
if diff<0:
seqs[0][-1] += -diff
else:
seqs[1][-1] += diff
return sum(seqs[0]), sum(seqs[1]), seqs[0], seqs[1]

if __name__=="__main__":

for i in range(10):
s0, s1, seq0, seq1 = make_sequence()
t0, t1 = make_teams(seq0+seq1)
print s0, s1, t0, t1
if s0 != t0 or s1 != t1:
print "FAILURE", s0, s1, t0, t1
``````

``````def make_teams2(que):
que.sort()
if len(que)%2: que.insert(0,0)
t1 = []
t2 = []
while que:
if len(que) > 2:
t1.append(que.pop(0))
t1.append(que.pop())
t2.append(que.pop(0))
t2.append(que.pop())
else:
t1.append(que.pop(0))
t2.append(que.pop())
print sum(t1), sum(t2), "\n"
``````

``````import random
def f(data, nb_iter=20):
diff = None
sums = (None, None)
for _ in xrange(nb_iter):
random.shuffle(data)
mid = len(data)/2
sum1 = sum(data[:mid])
sum2 = sum(data[mid:])
if diff is None or abs(sum1 - sum2) < diff:
sums = (sum1, sum2)
print sums
``````

``````class Team(object):
def __init__(self):
self.members = []
self.total = 0

self.members.append(m)
self.total += m

def __cmp__(self, other):
return cmp(self.total, other.total)

def make_teams(ns):
ns.sort(reverse = True)
t1, t2 = Team(), Team()

for n in ns:
t = t1 if t1 < t2 else t2

return t1, t2

if __name__ == "__main__":
import sys
t1, t2 = make_teams([int(s) for s in sys.argv[1:]])
print t1.members, sum(t1.members)
print t2.members, sum(t2.members)

>python two_piles.py 1 50 50 100
[50, 50] 100
[100, 1] 101
``````

``````def make_teams(que):
que.sort()
t1, t2 = []
while que:
t1.append(que.pop())
if sum(t1) > sum(t2):
t2, t1 = t1, t2
print min(sum(t1),sum(t2)), max(sum(t1),sum(t2))
``````