Partition Problem

Alex Martelli aleaxit at yahoo.com
Mon Jul 16 08:30:13 EDT 2001


"Donovan Hide" <donovanhide at bigfoot.com> wrote in message
news:9itb14$2oi$1 at newsg1.svr.pol.co.uk...
    ...
> question. What I am actually looking for is the enumeration of all the 6
> whole numbers greater than 0 that sum to 17.
>     After that, another enumeration is required, this time to find all 6
> whole numbers greater than 0 that sum to 20. Order is unimportant.
    ...
>     So, apart from this short bibliography, I am still stuck. I don't want

So go back to the solution I already posted for a slightly
different interpretation of your problem:

def seqs(i, j, sumsofar, sumdesired, minok, thelist):
    # print 's',i,j,sumsofar,sumdesired,minok,thelist[:j]
    if i==j-1:
        missing = sumdesired - sumsofar
        if missing < minok: return 0
        thelist[i] = missing
        print thelist
        return 1
    elif i>=j or sumsofar+minok > sumdesired:
        return 0
    thelist[i] = minok
    results = 0
    while 1:
        more = seqs(i+1, j, sumsofar+thelist[i], sumdesired,
            thelist[i]+1, thelist)
        if not more: break
        results += more
        thelist[i]+=1
    return results

Apparently the only way in which this differs from what
you'd like to do is that this forbids duplication, right?
OK, then, so ALLOW duplication -- where's the problem?!
Just change the recursive call so that the 5th parameter,
'minok', is passed as thelist[i] rather than thelist[i]+1.

This means thelist ends up in nondecreasing, rather than
strictly increasing, order.

def seqs1(i, j, sumsofar, sumdesired, minok, thelist):
    # print 's',i,j,sumsofar,sumdesired,minok,thelist[:j]
    if i==j-1:
        missing = sumdesired - sumsofar
        if missing < minok: return 0
        thelist[i] = missing
        print thelist
        return 1
    elif i>=j or sumsofar+minok > sumdesired:
        return 0
    thelist[i] = minok
    results = 0
    while 1:
        more = seqs1(i+1, j, sumsofar+thelist[i], sumdesired,
            thelist[i], thelist)
        if not more: break
        results += more
        thelist[i]+=1
    return results

if __name__=='__main__':
    nr = seqs1(0, 6, 0, 17, 1, 6*[0])
    print nr,'sets of 6 numbers that sum to 17'

D:\py21>python sq.py
[1, 1, 1, 1, 1, 12]
[1, 1, 1, 1, 2, 11]
    ...snipped several lines...
[2, 2, 3, 3, 3, 4]
[2, 3, 3, 3, 3, 3]
44 sets of 6 numbers that sum to 17

D:\py21>


So, where's the problem?  Solving this for sets of 6
numbers that sum to 20 is left as an exercise for the
reader -- not too difficult an exercise, I hope!-)
(More interesting is to find optimizations that can
be applied to this reference implementation:-).

Another easy exercise: what would you change if the
numbers were allowed to be from -1 upwards, rather
than "greater than 0"...?


General consideration: even where the problem statement
does NOT constrain the order of the results (you just
have to count them, whatever), it's often easier if
results are generated in a systematic order -- this helps
ensure against double-counting, you can print out the
results you're supposed to be just-counting to help
you debug things (and notice gaps more easily because
of the systematic order, if you have a bug somewhere)...


Alex






More information about the Python-list mailing list