Improve this recursive code please!

Sean Ross frobozz_electric at hotmail.com
Fri May 9 12:35:41 EDT 2003


Hi.

I've been thinking about this problem for several days. Unfortunately, I
haven't found a solution for you, but I have found the form of a solution
that perhaps someone else here will know how to implement:

for arrangement in xuniquepermute(xdistribute(items, bins)):
    print arrangement  # or perform some other operations with this
arrangement

xdistribute(items, bins) would be a generator function that returns, one by
one, the ways to distribute items in bins, and xuniquepermute() would
return, one by one, the unique permutations for each distribution.

I have a version of distribute that does not do what I want, but does show
what I mean when I say that it shows "the ways to distribute items in bins".
Preferably, this could be changed into a generator function, and perhaps one
that is iterative, to avoid the maximum recursion depth issue.

# credit: based on Java version by Dr. Jason Morrison
def distribute(items, bins):
    def __distribute(accum, maxvalue, subtotal, spots):
        remaining = items - subtotal
        if spots == 1:
            print accum + [remaining]
        else:
            smallest, remainder = divmod(remaining, spots)
            if remainder:
                smallest += 1
            for i in xrange(maxvalue, smallest-1, -1):
                __distribute(accum + [i], min(i,remaining-i),
                             subtotal + i, spots-1)

    __distribute([],items,0,bins)

distribute(items=5, bins=3)


# this outputs
[5, 0, 0]
[4, 1, 0]
[3, 2, 0]
[3, 1, 1]
[2, 2, 1]

Once you have this, you'd need to use xuniquepermute() to generate things
like, for instance,

[5, 0, 0], [0, 5, 0], [0, 0, 5]

since it's a different arrangement when the items are packed into a
different bin. An xpermute() function exists, but this will not generate the
information you need as it will return

[5, 0, 0], [5, 0, 0], [0, 5, 0], [0, 0, 5], [0, 5, 0], [0, 0, 5]

I haven't been able to implement either xdistribute() or xuniquepermute()
myself, although I will keep trying because I think the idea is sound and
would work as a solution to your problem. I would be relieved to see an
implementation of this, as it's become something of an itch for me.

Sorry I couldn't be of more assistance,
Sean


"waxmop" <waxmop at sarcastic-horse.com> wrote in message
news:3EB7DF65.55A50CD4 at sarcastic-horse.com...
> Hi - I wrote a program that gets two arguments: numbricks, and numbins.
> The program calculates every possible way to distribute all the bricks
> into the bins, using a recursive function.
>
> The program works ok, especially when numbricks and numbins are under 5
> each.  However, I need to run this program when numbricks = 100 or more,
> and I'm concerned about memory issues.
>
> Is there a way I can avoid building a giant stack?  This program doesn't
> need to run fast at all.  It just needs to run with enormous numbers of
> bricks and bins, even if it takes a few hours.  I just don't want to
> overload our server while it's happening.
>
> Finally. I do have access to a beowulf cluster; is this something that
> could take advantage of that?
>
> I'm still learning python, so other comments about the code are
> welcomed.  And no, this isn't a homework assignment.
>
> The program can be run like so:
>
> ./tupp.py 4 4
>
> or
>
> ./tupp.py -help
>
> to get a usage message.
>
>
> Here's the program:
>
> #! /usr/bin/env python
>
> import sys
> import types
> import string
>
> def mk_tree(numbricks, numbins):
>   bin = [0]*numbins
>   results = {}
>   mk_tree_r(numbricks, numbins, bin, results)
>   tups = results.keys()
>   tups.sort()
>   tups.reverse()
>   return tups
>
>
> def mk_tree_r(numbricks, numbins, bin, results):
>   if countbricks(bin) < numbricks:
>     for i in range(numbins):
>       bin[i] += 1
>       mk_tree_r(numbricks, numbins, bin, results)
>       bin[i] -= 1
>   else:
>     t = tuple(bin)
>     results[t] = 1
>
>
> def countbricks(bin):
>   sum = 0
>   for bricks in bin:
>     if bricks:
>       sum += bricks
>   return sum
>
>
> #main method:
> def main():
>
>   usage = """
>       USAGE: python %s <number of bricks> <number of bins>
>         <number of bricks> must be an integer.
>         <number of bins> must also be an integer.
>     """ % sys.argv[0]
>
>   try:
>     numbricks = string.atoi(sys.argv[1])
>     if type(numbricks) is not types.IntType: raise
>     numbins = string.atoi(sys.argv[2])
>     if type(numbins) is not types.IntType: raise
>   except:
>     raise SystemExit, usage
>
>   t = mk_tree(numbricks, numbins)
>   f = open('tuples.txt', 'w')
>   for tup in t:
>     print >> f, tup
>   f.close()
>   print "wrote a total of %d tuples to tuples.txt" % len(t)
>
> if __name__ == '__main__': main()
>
>
>






More information about the Python-list mailing list