My solution first divides people into their families. I build up a list of santas (where each person gives to the next in the list, and the tail gives to the head) by: 1) For the first santa, choose from the family with the most people. 2) For all other santas, choose from the family with the most remaining people that is not the family of the last santa. I wasn't able to think of any situations that would thwart this strategy. I, too, just print out the names at the console instead of e-mailing. And there is also nothing random about my strategy, so given the same input you will always get the same output. It would be a simple matter to shuffle the members within the families though; that would mix things up a little. Note to other submitters, the following is a good edge case to test: Luke1 Skywalker <luke / theforce.net> Luke2 Skywalker <luke / theforce.net> Luke3 Skywalker <luke / theforce.net> Luke4 Skywalker <luke / theforce.net> Leia Skywalker <leia / therebellion.org> Toula Portokalos <toula / manhunter.org> Gus Portokalos <gus / weareallfruit.net> Bruce Wayne <bruce / imbatman.com> Virgil Brigman <virgil / rigworkersunion.org> --- # Represents a family. class Family attr_reader :name, :members def initialize(name) @name = name @members = [] end # Number of people in family. def count @members.length end # Pop the last member off. def pop @members.pop end # Compare by size. def <=>(other) count <=> other.count end end class Person attr_reader :first_name, :last_name, :email def initialize(first_name, last_name, email) @first_name = first_name @last_name = last_name @email = email end def to_s "#{@first_name} #{@last_name} <#{@email}>" end end familyTable = Hash.new {|h,k| h[k] = Family.new(k)} while line = gets line =~ /(\w+) (\w+) <(.+)>/ first, last, email = $1, $2, $3 familyTable[last].members << Person.new(first, last, email) end puts puts "Processing..." families = familyTable.values santas = [] while families.length > 0 families.sort!.reverse! if families.first.count == 0 # nobody is left; we're done break end if santas.length == 0 # for the very first santa, choose someone from # the largest family santas << families.first.pop else success = false # find largest family that is not one's own families.each do |family| if family.name != santas.last.last_name santas << family.pop success = santas.last break end end raise "No solution." unless success end end puts "Success!" puts lastSanta = santas.last santas.each do |santa| puts santa.to_s + " => " + lastSanta.to_s lastSanta = santa end