Here's a brute force quadratic solution to the original problem, a linear solution to the original problem, and a brute force and generic linear solution for three groups.
import numpy as np
N = 20
G = 3
MINSEP = 4
def solve_cubic(a):
r = range(N - G + 1)
return max(
(
(a[i:i+G]+a[j:j+G]+a[k:k+G]).sum(), i, j, k
) for i in r for j in r for k in r if (
i + G + MINSEP <= j and j + G + MINSEP <= k))
def solve_quadratic(a):
r = range(N - G + 1)
return max(
(a[i:i+G].sum() + a[j:j+G].sum(), i, j) for i in r for j in r if (
j-i > G+MINSEP-1))
def solve_linear(a):
sumc = np.cumsum(a)
sumc = np.array([0] + sumc.tolist())
sumg = sumc[G:] - sumc[:-G]
rmax = np.maximum.accumulate(sumg[::-1])[::-1]
scores = sumg[:-(MINSEP+G)] + rmax[(MINSEP+G):]
i = np.argmax(scores)
j = i + MINSEP + G + np.argmax(sumg[i + MINSEP + G:])
return scores[i], i, j
def solve_linear_generic(numbers, groups):
sumc = np.cumsum([0] + list(numbers))
sumg = sumc[G:] - sumc[:-G]
table = {}
trace = {}
for a in range(N - G + 2):
a_prime = a - MINSEP - G
for b in range(groups + 1):
if a == 0:
table[a, b] = 0 if b == 0 else -1
trace[a, b] = ()
else:
c0 = table[a-1, b]
tracec0 = trace[a-1, b]
if b == 0:
table[a, b] = c0
trace[a, b] = tracec0
else:
c1 = sumg[-a]
tracec1 = (N - G + 1 - a,)
if a_prime >= 0:
c1 += table[a_prime, b-1]
tracec1 = tracec1 + trace[a_prime, b-1]
if c0 < c1:
table[a, b] = c1
trace[a, b] = tracec1
else:
table[a, b] = c0
trace[a, b] = tracec0
return (table[N - G + 1, groups],) + trace[N - G + 1, groups]
def main():
a = np.random.randint(100, size=N)
print a
print 'two groups:'
print solve_quadratic(a)
print solve_linear(a)
print solve_linear_generic(a, 2)
print 'three groups:'
print solve_cubic(a)
print solve_linear_generic(a, 3)
main()