发红包问题

编程那点事

看到了有人说提红包问题,通过偏移量改变随机区间,最后一次为补偿,如果随机失败(前面偏移量太大)则重新生成,然后加了Foo类,通过提高补偿率提高计算效率,

class Package
  def initialize total, num, min, max
    @total = total
    @package_num = num
    @max = max
    @min = min
    @origin_base = total / num
  end

  def generate_package
    packages = []
    @package_num.times do |i|
      new_package = random_package
      if @package_num == 1
        packages << @total.round(2)
        @total = 0
        @package_num -= 1
        next
      end
      packages << new_package
      @total -= new_package
      @package_num -= 1
    end
    packages
  end

  private
  def low_rate
    (@max - @origin_base).to_f / (@max - @min).to_f
  end

  def random_heigh
    if offset_rate > 0
      rand((@origin_base.to_f + (@max - @origin_base) * offset_rate)..@max.to_f).round 2
    else
      rand(@origin_base.to_f..(@max.to_f + (@max - @origin_base) * offset_rate)).round 2
    end
  end

  def random_low
    if offset_rate > 0
      rand((@min.to_f + (@origin_base - @min) * offset_rate)..@origin_base.to_f).round 2
    else
      rand(@min.to_f..(@origin_base.to_f + (@origin_base - @min) * offset_rate)).round 2
    end
  end

  def offset_rate
    rate = ((@total / @package_num) - @origin_base) / @origin_base
    raise if rate > 1 || rate < -1
    -rate
  end·

  def random_package
    rand(0.0..1.0) <= low_rate ? random_low : random_heigh
  end
end

class Foo
  # 分批生成红包,提高补偿比例,提升效率
  def initialize(total, num, min, max)
    @total = total
    @num = num
    @min = min
    @max = max
    @avg = total / num
  end

  def optimized_generate
    num_10 = @total / 10
    num_left = @total % 10
    packages = []
    num_10.times do
      packages << get_packages(10 * @avg, 10)
    end
    packages << get_packages(num_left * @avg, num_left) if num_left > 0
    packages.flatten
  end
  def get_packages sub_total, sub_num
    while true do·
      begin
        packages = Package.new(sub_total, sub_num, @min, @max).generate_package
        return packages if packages.sum == sub_total
      rescue
      end
    end
  end
end
time_start = Time.now.to_f
result = Foo.new(100000, 50000, 1, 5).optimized_generate
time_end = Time.now.to_f
p result
puts "package count: " + result.length.to_s
puts "package sum: " + result.sum.to_s
puts "cost time: #{time_end - time_start}s"

发表于 2018.11.30