I don't have a specific solution for you yet, but I can point you in the right direction.
I threw your code into irb and ran it through RubyProf. RubyProf will tell you where the bottlenecks in your code are and help you optimize it.
I copied your code into IRB, then ran the following script:
require 'ruby-prof'
result = RubyProf.profile do
20.sum_combination
end
printer = RubyProf::FlatPrinter.new(result)
printer.print(STDOUT)
The output is:
%self total self wait child calls name
37.03 0.160 0.096 0.000 0.064 15390 Array#hash
24.57 0.064 0.064 0.000 0.000 104648 Kernel#hash
12.37 0.055 0.032 0.000 0.023 11754 Array#eql?
8.71 0.023 0.023 0.000 0.000 36146 Numeric#eql?
6.74 0.233 0.018 0.000 0.216 17 Array#uniq
6.31 0.026 0.016 0.000 0.009 98 Array#map
3.59 0.009 0.009 0.000 0.000 7695 Array#sort
0.16 0.000 0.000 0.000 0.000 636 Fixnum#==
0.15 0.000 0.000 0.000 0.000 17 Array#flatten
0.04 0.260 0.000 0.000 0.260 1 Object#irb_binding
0.02 0.260 0.000 0.000 0.260 99 *Integer#sum_combination
0.01 0.000 0.000 0.000 0.000 17 Float#ceil
0.01 0.000 0.000 0.000 0.000 17 Hash#[]=
0.01 0.000 0.000 0.000 0.000 17 Fixnum#/
0.01 0.200 0.000 0.000 0.200 34 *Integer#downto
0.00 0.200 0.000 0.000 0.200 17 *Enumerator#each
0.00 0.200 0.000 0.000 0.200 17 *Enumerable#map
As you can see, the vast majority of your time is spent in #hash and #eql?, which are called by sort, uniq, and possibly flatten. That suggests that finding ways to avoid uniquifying the data until you've completed the algorithm would be much more efficient.
If you can refactor your code to avoid calling sort, flatten, and uniq on every run, that would speed things up significantly.