找到散列的组合以匹配所需的值的百分比分布

时间:2019-07-10 13:13:48

标签: ruby algorithm random language-agnostic combinations

考虑到散列数组,我正在寻找一种选择这些散列的随机子集的方法,以使子集的属性分布与所需百分比匹配。

例如,给定以下数组:

[
  {
    question_id: 1,
    grade: 1,
    marks: [
      { topic: 'number', ao: 1 },
      { topic: 'ratios', ao: 2 }
    ]
  },
  {
    question_id: 2,
    grade: 3,
    marks: [
      { topic: 'number', ao: 2 },
      { topic: 'number', ao: 2 }
    ]
  },
  {
    question_id: 3,
    grade: 2,
    marks: [
      { topic: 'number', ao: 1 },
      { topic: 'geometry', ao: 1 },
      { topic: 'ratios', ao: 1 },
      { topic: 'number', ao: 2 },
      { topic: 'geometry', ao: 2 }
    ]
  },
  {
    question_id: 4,
    grade: 3,
    marks: [
      { topic: 'number', ao: 1 },
      { topic: 'ratios', ao: 2 },
      { topic: 'geometry', ao: 2 },
      { topic: 'geometry', ao: 2 }
    ]
  },
  {
    question_id: 5,
    grade: 1,
    marks: [
      { topic: 'ratios', ao: 1 },
      { topic: 'ratios', ao: 2 }
    ]
  },
  {
    question_id: 6,
    grade: 1,
    marks: [
      { topic: 'number', ao: 1 },
      { topic: 'number', ao: 2 },
      { topic: 'number', ao: 2 },
      { topic: 'ratios', ao: 2 }
    ]
  },
  {
    question_id: 7,
    grade: 3,
    marks: [
      { topic: 'number', ao: 2 }
    ]
  },
  {
    question_id: 8,
    grade: 3,
    marks: [
      { topic: 'geometry', ao: 1 }
    ]
  }
]

我想找到一个满足以下条件的随机组合:

总分数= 10

50%的标记是主题编号
20%的分数是主题比率
30%的标记是主题几何

40%的分数是1级
50%的分数是2级
10%的分数是3年级

50%的分数是1分
50%的分数是ao 2

满足这些要求的示例结果是:

[
  {
    question_id: 3,
    grade: 2,
    marks: [
      { topic: 'number', ao: 1 },
      { topic: 'geometry', ao: 1 },
      { topic: 'ratios', ao: 1 },
      { topic: 'number', ao: 2 },
      { topic: 'geometry', ao: 2 }
    ]
  },
  {
    question_id: 6,
    grade: 1,
    marks: [
      { topic: 'number', ao: 1 },
      { topic: 'number', ao: 2 },
      { topic: 'number', ao: 2 },
      { topic: 'ratios', ao: 2 }
    ]
  },
  {
    question_id: 8,
    grade: 3,
    marks: [
      { topic: 'geometry', ao: 1 }
    ]
  }
]

理想情况下,如果不存在满足这些要求的组合(具有一定程度的容忍度),我希望会收到一个错误。

我最初的解决方法是找到所有可能的问题组合,总计10分,然后迭代这些组合并检查每个组合是否满足所有其他要求。

我从这种算法开始,该算法从数组中查找所有可能的数字组合,以求和成所需的总数:

def subset_sum(numbers, target, partial=[], result=[])
    s = partial.inject 0, :+

    if s == target
      result << partial
    end

    return if s >= target

    (0..(numbers.length - 1)).each do |i|
      n = numbers[i]
      remaining = numbers.drop(i+1)
      subset_sum(remaining, target, partial + [n], result)
    end

    result
  end
end

但是,在我的问题的实际应用中,我希望问题数组的长度超过1000,并且标记总数等于40。对于这些数字,此解决方案还没有经过优化,运行时间也很长。

0 个答案:

没有答案