------art_24293_8967625.1139164490340
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: base64
Content-Disposition: inline

TXkgc29sdXRpb24gaXMgYXR0YWNoZWQuICBJdCBzb2x2ZXMgdmlhIHJlY3Vyc2lvbiB3aXRoIGEg
ZmV3Cm9wdGltaXphdGlvbnMgKGl0IGlzIHN0aWxsIHJlYWxseSBzbG93LCB0aG91Z2gpCgogKiBp
dCBjaGVja3MsIGlmIHRoZSBzdW0gb2YgYWxsIHBpZWNlcyBpcyBkaXZpc2FibGUgYnkgdGhlIG51
bWJlciBvZiBwZXJzb25zLAogICBpZiBub3QsIHRoZW4gdGhlcmUgaXMgbm8gc29sdXRpb24uCiAq
IGl0IGF2b2lkcyBnaXZpbmcgZXZlcnkgcGllY2UgdG8gdGhlIGZpcnN0IHBlcnNvbiBhdCB0aGUg
YmVnaW5uaW5nCgpUd28gaW50ZXJlc3RpbmcgbWV0aG9kcyBJIHVzZWQ6CgogIG1vZHVsZSBFbnVt
ZXJhYmxlCiAgICBkZWYgYWxsX2VxdWFsPwogICAgICBzZWxmLmluamVjdCB7IHxhLGJ8IGJyZWFr
IGZhbHNlIHVubGVzcyBhID09IGI7IGIgfSAhPSBmYWxzZSB9CiAgICBlbmQKICBlbmQKICBbMywz
LDMsM10uYWxsX2VxdWFsPyAjPT4gdHJ1ZQoKICBjbGFzcyBPYmplY3QKICAgIGRlZiBpZl9mYWxz
ZTsgc2VsZiA/IHNlbGYgOiB5aWVsZDsgZW5kOwogIGVuZAoKVGhpcyB3b3JrcyBuaWNlbHkgZm9y
IEVudW1lcmFibGUjZmluZDoKCiAgWzEsMiwzLDQsNV0uZmluZCB7fHh8IHggPiAxMH0uaWZfZmFs
c2UgeyB3YXJuICJub3RoaW5nIGZvdW5kIjsgLTEgfSAjPT4gLTEKCi1MZXZpbgo------art_24293_8967625.1139164490340
Content-Type: application/octet-stream; name=q65_levin_alexander.rb
Content-Transfer-Encoding: 7bit
X-Attachment-Id: f_ejboxomp
Content-Disposition: attachment; filename="q65_levin_alexander.rb"

# 
# Rubyquiz #65 (Splitting the Loot)
# Levin Alexander <levin / grundeis.net>
#

module Enumerable
  def sum; inject { |a,b| a+b } end

  def all_equal?
    inject { |a,b| break false unless a b; b } ! alse
  end
end

class Object
  def if_false
    self ? self : yield
  end
end

class Symbol
  def to_proc; proc { |obj| obj.send(self) }; end
end

class Array
  def rest; self[1..-1]; end
end


class LootDistributor
  include Enumerable

  def initialize(persons, pieces)
    @pieces  ieces.sort.reverse # distribute big pieces first
    @persons  ersons
  end

  def each(&blk)
    dist  rray.new(@persons) { [] }
    sums  rray.new(@persons) { 0 } # avoid recalculating the sums

    # special case
    return unless (@pieces.sum % @persons) 0
    
    distribute(0, sums, dist, @pieces, &blk)
  end
  
  private
  
  def distribute(depth, sums,dist,remaining_pieces,&blk)
    if remaining_pieces.empty? 
      yield dist if sums.all_equal?
    else
      first_piece, rest  emaining_pieces.first, remaining_pieces.rest
      
      (0...@persons).each { |p|
        # start with a different person at every turn so that we 
        # don't end up giving everything to the first guy
        # in the beginning
        # 
        p  p+depth) % @persons

        dist[p].push first_piece
        sums[p] + irst_piece

        # recursively distribute the rest
        # 
        distribute(depth+1, sums, dist, rest, &blk)
  
        # undo everything.  This avoids having to duplicate the arrays
        # 
        dist[p].pop
        sums[p] - irst_piece
      }
    end
  end
end

if __FILE__ $0
  
  persons  RGV.shift.to_i
  loot  RGV.map(&:to_i)

  LootDistributor.new(persons, loot).find { |dist|
      dist.each_with_index { |pieces,person|
      puts "#{person}: #{pieces.join(' ')}"
    }
  }.if_false {
    warn "It is not possible to fairly split this treasure #{persons} ways"
  }

end


------art_24293_8967625.1139164490340--