给定一个带有 n 元素的集合,我需要找到该集合的所有分区,其中 k 子集的大小几乎相等。
例如,对于具有7个元素和3个子集的集合,我只需要分区,其中有两个子集,每个子集有2个元素,一个子集有3个元素。我不希望分区具有包含1,2和4个元素的子集。
换句话说,对于一组7个元素有877 possible partitions,但我只对组成具有2/2/3元素的子集的105(?)分区感兴趣:
实际上 n 大约是35,这意味着大约有2.81 * 10 27 分区,“仅”8,338,573,669,964,101 partitions with three subsets。因此,我无法计算所有这些,并悄悄找到我想要的那些。
只计算感兴趣的分区的算法是什么?(不是分区的数量,而是每个分区的每个子集中的实际成员。)
答案 0 :(得分:4)
这是一个很好的方法,只需要通过保持排序来生成所有可能性,以及快速计算答案数量的方法:
def enum(n, k)
# Pick smaller_size items from the list, repeat smaller_n times
# then pick larger_size items from the list, repeat larger_n times.
smaller_n = n.div k
larger_times = n % k
smaller_times = k - larger_times
larger_n = smaller_n + 1
return to_enum(:enum, n, k) { calc_size(n, smaller_n, smaller_times, larger_n, larger_times) } unless block_given?
all = [*1..n]
# split all into one subset to group with the smaller_n and another
# to group with the larger_n.
all.combination(smaller_n * smaller_times).each do |smaller|
larger = all - smaller
subdivide(smaller, smaller_n) do |small|
subdivide(larger, larger_n) do |large|
yield [*small, *large]
end
end
end
end
# Subdivides elems into groups of n, keeping the elements sorted
# and generating only the sorted such combinations.
def subdivide(elems, n)
return yield [] if elems.empty?
# No choice for the first element, because we want to keep things sorted.
first, *rest = elems
rest.combination(n - 1).each do |comb|
remain = rest - comb
subdivide(remain, n) do |sub|
yield [[first, *comb], *sub]
end
end
end
def calc_size(n, smaller_n, smaller_times, larger_n, larger_times)
all = [
smaller_times.times.map do |i|
Array.new(n - i*smaller_n).combination(smaller_n)
end,
larger_times.times.map do |i|
Array.new(n - smaller_times*smaller_n - i*larger_n).combination(larger_n)
end
]
# Multiply everything, but divide by the number of symmetries, because
# we don't want to distinguish (1,2), (3,4), ... from (3,4), (1,2), ...
all.map do |enums|
enums.map(&:size).inject(1, :*) / enums.permutation.size
end.inject(:*)
end
p enum(7, 3).size # => 105 (instant)
p enum(7, 3).first(5) # => [[[1, 2], [3, 4], [5, 6, 7]],
# [[1, 3], [2, 4], [5, 6, 7]],
# [[1, 4], [2, 3], [5, 6, 7]],
# [[1, 2], [3, 5], [4, 6, 7]],
# [[1, 3], [2, 5], [4, 6, 7]]]
p enum(7, 3).count # => 105 (quick)
p enum(35, 3).size # => 564121960420200 (instant)
p enum(35, 3).first(2) # => [[[1..11], [12..23], [24..35]],
# [[1..11], [12..22, 24], [23, 25..35]]]
p enum(35, 3).count # => will take forever, should return 564121960420200
注意:只是为了踢,这也可以通过构建一些枚举器并使用size
来懒惰地计算大小,而无需迭代它们。这仅适用于Ruby 2.0+,因为它需要Enumerator#size
。
增加乐趣:
require 'with_progress'
enum(16, 3).with_progress.count # => enjoy!
答案 1 :(得分:2)
重要观察:在分区大小差异不超过1的情况下,分区大小的多分区是唯一定义的。我们有(n % k)
部分大小为ceil(n / k)
和(k - n % k)
个大小为floor(n / k)
的分区。
因此,让我们修复分区大小,并枚举所有分区的所有可能子集:
@n = n = 7
@k = k = 3
@used = n.times.map { false }
# @sizes = [2,2,3] for n = 7, k = 3
@sizes = (k - n % k).times.map { n / k } + (n % k).times.map { (n + k - 1) / k }
@parts = @sizes.map { |i| [0]*i }
def enumerate_part(i, j, lo, y)
# i = index of the current part
# j = index of the current number in the current part
# lo = lower bound for numbers to chose
# y = output yielder
if i == @parts.size
y << @parts.map(&:dup)
return
end
if j == @sizes[i]
enumerate_part(i + 1, 0, @sizes[i + 1] == @sizes[i] ? @parts[i][0] : 1, y)
return
end
(lo..@n).each do |x|
next if @used[x]
@used[x] = true
@parts[i][j] = x
enumerate_part(i, j + 1, x + 1, y)
@used[x] = false
end
end
results = Enumerator.new { |y| enumerate_part(0,0,1,y) }
puts results.count
请注意,对于相同大小的分区,我为它们分配增加的最小值以实现唯一性。这可能导致一些回溯(最多2个级别),因此它不是最佳的。我们可能希望避免分配数字,我们已经知道下限对于下一个同样大小的分区来说太高了。那时候有点复杂,所以我保持简单。绝对有可能改善这一点。
它仅使用 O(n)空间,因为我改变全局状态而不是复制东西(是的,我向枚举器提供防御性副本,但如果你处理结果则没有必要立即在每次迭代中)。也许不是最优雅的解决方案,但目标是实现良好的速度。
输出:
105
使用较大的 n (超过20)运行此功能并不好玩。我责怪Ruby,但幸运的是,这个特定的实现在几乎任何其他语言中看起来都非常相似。
更新:为了好玩,我将算法改进为输出大小完全线性(除了潜在的 n 因素,因为保留了剩余数字的集合)。它应该快几倍:
def dfs(i, j, lo, eq, sz, state)
parts, y, n, k, left = state
if i == k
y << parts
return
end
if j == sz
mid = i+1 == n % k
neweq, newsz = mid ? [k - i - 1, sz-1] : [eq - 1, sz]
dfs(i+1, 0, mid ? 1 : parts[i][0], neweq, newsz, state)
return
end
higher = ((j == 0) ? (eq * sz - j - 1) : (sz - j - 1))
left.drop(higher).each_with_index do |x,idx|
break if x < lo
parts[i][j] = x
left.delete_at(idx + higher)
dfs(i, j + 1, x + 1, eq, sz, state)
left.insert(idx + higher, x)
end
end
def niklas(n, k)
parts = k.times.map{|i| [0]*(i < n%k ? (n+k-1)/k : n/k) }
left = n.downto(1).to_a
results = Enumerator.new { |y|
dfs(0, 0, 1, (n % k == 0) ? k : n % k, (n + k - 1) / k, [parts, y, n, k, left])
}
cnt = results.count
puts "count = #{cnt} != #{@sz}" unless cnt == @sz
end
答案 2 :(得分:1)
我相信这个解决方案(在基准测试中称为“cary1”)将完成这项工作:
<强>代码强>
require 'set'
def doit(items, subs, so_far=[], combos=Set.new)
return combos << (so_far+[items]).to_set if subs.size == 1
items.combination(subs.first){|c|doit(items-c,subs[1..-1],so_far+[c],combos)}
combos
end
<强>演示强>
doit([1,2,3,4,5], [2,3]).to_a.map(&:to_a) # 10 combinations
#=> [[[1, 2], [3, 4, 5]], [[1, 3], [2, 4, 5]], [[1, 4], [2, 3, 5]],
# [[1, 5], [2, 3, 4]], [[2, 3], [1, 4, 5]], [[2, 4], [1, 3, 5]],
# [[2, 5], [1, 3, 4]], [[3, 4], [1, 2, 5]], [[3, 5], [1, 2, 4]],
# [[4, 5], [1, 2, 3]]]
doit([1,2,3,4,5], [2,1,2]).to_a.map(&:to_a) # 15 combinations
#=> [[[1, 2], [3], [4, 5]], [[1, 2], [4], [3, 5]], [[1, 2], [5], [3, 4]],
# [[1, 3], [2], [4, 5]], [[1, 3], [4], [2, 5]], [[1, 3], [5], [2, 4]],
# [[1, 4], [2], [3, 5]], [[1, 4], [3], [2, 5]], [[1, 4], [5], [2, 3]],
# [[1, 5], [2], [3, 4]], [[1, 5], [3], [2, 4]], [[1, 5], [4], [2, 3]],
# [[2, 3], [1], [4, 5]], [[2, 4], [1], [3, 5]], [[2, 5], [1], [3, 4]]]
doit([1,2,3,4,5,6,7], [2,2,3]).to_a.map(&:to_a) # 105 combinations
# => [[[1, 2], [3, 4], [5, 6, 7]], [[1, 2], [3, 5], [4, 6, 7]],
# [[1, 2], [3, 6], [4, 5, 7]], [[1, 2], [3, 7], [4, 5, 6]],
# [[1, 2], [4, 5], [3, 6, 7]], [[1, 2], [4, 6], [3, 5, 7]],
# ...
# [[4, 5], [6, 7], [1, 2, 3]], [[4, 6], [5, 7], [1, 2, 3]],
# [[4, 7], [5, 6], [1, 2, 3]]]
说明
subs
视为给定,因为构建subs
似乎是一个单独且不是非常困难的问题。[[1],[2,3],[4]]
和[[4],[2,3],[1]]
都包含在结果中,我将这两个转换为集合。尝试将这些添加到一组结果时,只会添加第一个结果。我使用集合是因为没有说出给定集合的元素,特别是每个对是否可以与<=>
进行比较。根据结果的使用方式,将结果保留为一组集可能就足够了。或者,可以很容易地将这组集合转换为数组数组,正如我在“演示”部分中所做的那样。如果subs
中没有doit()
,则可以在调用doit
之前创建def divide_up(items, k)
m, r = items.size.divmod(k)
puts "m = #{m}, r = #{r}"
doit(items, Array.new(k-r, m) + Array.new(r, m+1))
end
:
demo
编辑:我做了一个小改动,让方法返回一组集合,认为这些可能直接使用。如果没有,可以很容易地将它们转换为数组数组,就像我在{{1}}部分中所做的那样。
答案 3 :(得分:1)
这是一种避免我的第一个解决方案执行不必要的枚举的方法。这种解决方案被称为“cary2&#39;在基准测试中。
<强>代码强>
def doit(list, group_sizes)
@group_sizes = group_sizes
@combos = []
@empty_group_filled_by_size = group_sizes.uniq.product([false]).to_h
recurse(list, group_sizes.map { |sub| [] })
@combos
end
def recurse(remaining_items_to_assign, assigned_so_far)
empty_group_filled_by_size = @empty_group_filled_by_size.dup
assigned_so_far.each_with_index do |group, ndx|
next if group.size == @group_sizes[ndx] # all positions in group allocated
if group.empty?
group_size = @group_sizes[ndx]
empty_group_filled_by_size[group_size] ? next :
empty_group_filled_by_size[group_size] = true
end
assigned_so_far[ndx] << remaining_items_to_assign.first
if remaining_items_to_assign.size == 1
@combos << assigned_so_far.map { |group| group.dup } # deep copy
else
recurse(remaining_items_to_assign[1..-1], assigned_so_far)
end
assigned_so_far[ndx].pop
end
end
<强>解释强>
假设我们有12个项目分配给3个大小为2的箱子(B2a,B2b和B2c)和两个大小为3的箱子(B3a和B3b)。项目按顺序分配到箱柜。
可以将第一个项目分配给2个区域(例如B2a)之一或3个区域之一(例如B3a)。它不能按顺序分配给给定大小的每个空仓,因为这会导致重复计算。对于分配给分档的每个给定项目,数组empty_group_filled_by_size
用于跟踪项目是否已分配给特定大小的第一个空分档。
第二项的分配可能性取决于哪个bin项目1已分配给。如果项目1已分配给B2a,则项目2可以分配给B2a,另外两个(仍为空)大小为2的箱子(比如B2b)或者分配到两个(空)大小3箱子中的一个(比如说B3a) )。如果项目1已分配给B3a,则可以将项目2分配给三个2个区域(例如B2a),B3a或B3b中的任何一个。
这些作业一直持续到只剩下一个要分配的项目为止,此时只有一个未装满的分区,并且它只有一个项目空间。在将项目分配保存到数组(@combos)中的bin之后,递归会回溯以考虑其他可能性。
答案 4 :(得分:0)
我认为对迄今为止贡献的三种解决方案进行基准测试可能会很有趣。如果有人想看到其他测试,请告诉我,我会添加它们。
<强> Niklas1 强>
def enumerate_part(i, j, lo, y)
# i = index of the current part
# j = index of the current number in the current part
# lo = lower bound for numbers to chose
# y = output yielder
if i == @parts.size
y << @parts.map(&:dup)
return
end
if j == @sizes[i]
enumerate_part(i + 1, 0, @sizes[i + 1] == @sizes[i] ? @parts[i][0] : 1, y)
return
end
(lo..@n).each do |x|
next if @used[x]
@used[x] = true
@parts[i][j] = x
enumerate_part(i, j + 1, x + 1, y)
@used[x] = false
end
end
def niklas1(n, k)
@n, @k = n, k
@used = n.times.map { false }
# @sizes = [2,2,3] for n = 7, k = 3
@sizes = (k - n % k).times.map { n / k } + (n % k).times.map { (n + k - 1) / k }
@parts = @sizes.map { |i| [0]*i }
results = Enumerator.new { |y| enumerate_part(0,0,1,y) }
cnt = results.count
puts "count = #{cnt} != #{@sz}" unless cnt == @sz
end
<强> Niklas2 强>
def dfs(i, j, lo, eq, sz, state)
parts, y, n, k, left = state
if i == k
y << parts
return
end
if j == sz
mid = i+1 == n % k
neweq, newsz = mid ? [k - i - 1, sz-1] : [eq - 1, sz]
dfs(i+1, 0, mid ? 1 : parts[i][0], neweq, newsz, state)
return
end
higher = ((j == 0) ? (eq * sz - j - 1) : (sz - j - 1))
left.drop(higher).each_with_index do |x,idx|
break if x < lo
parts[i][j] = x
left.delete_at(idx + higher)
dfs(i, j + 1, x + 1, eq, sz, state)
left.insert(idx + higher, x)
end
end
def niklas2(n, k)
parts = k.times.map{|i| [0]*(i < n%k ? (n+k-1)/k : n/k) }
left = n.downto(1).to_a
results = Enumerator.new { |y|
dfs(0, 0, 1, (n % k == 0) ? k : n % k, (n + k - 1) / k, [parts, y, n, k, left])
}
cnt = results.count
puts "count = #{cnt} != #{@sz}" unless cnt == @sz
end
<强>马克 - 安德烈强>
def enum(n, k)
# Pick smaller_size items from the list, repeat smaller_n times
# then pick larger_size items from the list, repeat larger_n times.
smaller_n = n.div k
larger_times = n % k
smaller_times = k - larger_times
larger_n = smaller_n + 1
return to_enum(:enum, n, k) { calc_size(n, smaller_n, smaller_times, larger_n, larger_times) } unless block_given?
all = [*1..n]
# split all into one subset to group with the smaller_n and another
# to group with the larger_n.
all.combination(smaller_n * smaller_times).each do |smaller|
larger = all - smaller
subdivide(smaller, smaller_n) do |small|
subdivide(larger, larger_n) do |large|
yield [*small, *large]
end
end
end
end
# Subdivides elems into groups of n, keeping the elements sorted
# and generating only the sorted such combinations.
def subdivide(elems, n)
return yield [] if elems.empty?
# No choice for the first element, because we want to keep things sorted.
first, *rest = elems
rest.combination(n - 1).each do |comb|
remain = rest - comb
subdivide(remain, n) do |sub|
yield [[first, *comb], *sub]
end
end
end
def calc_size(n, smaller_n, smaller_times, larger_n, larger_times)
all = [
smaller_times.times.map do |i|
Array.new(n - i*smaller_n).combination(smaller_n)
end,
larger_times.times.map do |i|
Array.new(n - smaller_times*smaller_n - i*larger_n).combination(larger_n)
end
]
# Multiply everything, but divide by the number of symmetries, because
# we don't want to distinguish (1,2), (3,4), ... from (3,4), (1,2), ...
all.map do |enums|
enums.map(&:size).inject(1, :*) / enums.permutation.size
end.inject(:*)
end
def marc_andre(n, k)
a = enum(n, k).to_a
a.size
end
<强> Cary1 强>
require 'set'
def cary1(n, k)
m, r = n.divmod(k)
cnt = doit([*1..n], Array.new(k-r, m) + Array.new(r, m+1)).to_a.map(&:to_a).size
puts "count = #{cnt} != #{@sz}" unless cnt == @sz
end
def doit(items, subs, so_far=[], combos=Set.new)
return combos << (so_far+[items]).to_set if subs.size == 1
items.combination(subs.first){|c|doit(items-c,subs[1..-1],so_far+[c],combos)}
combos
end
<强> Cary2 强>
def cary2(n, k)
m, r = n.divmod(k)
cnt = doit2([*1..n], Array.new(k-r, m) + Array.new(r, m+1)).to_a.map(&:to_a).size
puts "count = #{cnt} != #{@sz}" unless cnt == @sz
end
def doit2(list, group_sizes)
@group_sizes = group_sizes
@combos = []
@empty_group_filled_by_size = group_sizes.uniq.product([false]).to_h
recurse(list, group_sizes.map { |sub| [] })
@combos
end
def recurse(remaining_items_to_assign, so_far)
empty_group_filled_by_size = @empty_group_filled_by_size.dup
so_far.each_with_index do |group, ndx|
next if group.size == @group_sizes[ndx] # all positions in group allocated
if group.empty?
group_size = @group_sizes[ndx]
empty_group_filled_by_size[group_size] ? next :
empty_group_filled_by_size[group_size] = true
end
so_far[ndx] << remaining_items_to_assign.first
if remaining_items_to_assign.size == 1
@combos << so_far.map { |group| group.dup } # deep copy
else
recurse(remaining_items_to_assign[1..-1], so_far)
end
so_far[ndx].pop
end
end
基准代码
require 'benchmark'
def bench_it(n, k, iterations)
puts "\nn = #{n}, k = #{k}, size = #{@sz = marc_andre(n,k)}\n"
Benchmark.bm(%w[Niklas Marc-André Cary].map(&:size).max) do |bm|
bm.report('Niklas1') do
iterations.times do
niklas1(n, k)
end
end
bm.report('Niklas2') do
iterations.times do
niklas2(n, k)
end
end
bm.report('Marc-André') do
iterations.times do
marc_andre(n, k)
end
end
bm.report('Cary1') do
iterations.times do
cary1(n, k)
end
end
bm.report('Cary2') do
iterations.times do
cary2(n, k)
end
end
end
end
iterations = 1
bench_it( 7, 3, iterations)
bench_it(10, 2, iterations)
bench_it(10, 3, iterations)
bench_it(10, 4, iterations)
bench_it(13, 2, iterations)
bench_it(13, 3, iterations)
bench_it(13, 4, iterations)
bench_it(13, 5, iterations)
bench_it(16, 2, iterations)
bench_it(16, 3, iterations)
bench_it(16, 4, iterations)
bench_it(18, 2, iterations)
bench_it(18, 3, iterations)
bench_it(20, 2, iterations)
<强>结果
最好在后台播放this clip时阅读结果。
n = 7, k = 3, size = 105
user system total real
Niklas1 0.000000 0.000000 0.000000 ( 0.001131)
Niklas2 0.000000 0.000000 0.000000 ( 0.000595)
Marc-André 0.000000 0.000000 0.000000 ( 0.000911)
Cary1 0.000000 0.000000 0.000000 ( 0.003241)
Cary2 0.000000 0.000000 0.000000 ( 0.000922)
n = 10, k = 2, size = 126
user system total real
Niklas1 0.010000 0.000000 0.010000 ( 0.004986)
Niklas2 0.000000 0.000000 0.000000 ( 0.001031)
Marc-André 0.000000 0.000000 0.000000 ( 0.000880)
Cary1 0.000000 0.000000 0.000000 ( 0.003850)
Cary2 0.000000 0.000000 0.000000 ( 0.001607)
n = 10, k = 3, size = 2100
user system total real
Niklas1 0.040000 0.000000 0.040000 ( 0.042930)
Niklas2 0.010000 0.000000 0.010000 ( 0.012296)
Marc-André 0.020000 0.000000 0.020000 ( 0.017632)
Cary1 0.080000 0.000000 0.080000 ( 0.081082)
Cary2 0.020000 0.000000 0.020000 ( 0.018739)
n = 10, k = 4, size = 6300
user system total real
Niklas1 0.090000 0.000000 0.090000 ( 0.094029)
Niklas2 0.030000 0.000000 0.030000 ( 0.030908)
Marc-André 0.040000 0.000000 0.040000 ( 0.038247)
Cary1 0.510000 0.000000 0.510000 ( 0.512819)
Cary2 0.060000 0.000000 0.060000 ( 0.059061)
n = 13, k = 2, size = 1716
user system total real
Niklas1 0.210000 0.000000 0.210000 ( 0.219898)
Niklas2 0.020000 0.000000 0.020000 ( 0.017828)
Marc-André 0.020000 0.000000 0.020000 ( 0.015917)
Cary1 0.030000 0.000000 0.030000 ( 0.029272)
Cary2 0.020000 0.000000 0.020000 ( 0.022058)
n = 13, k = 3, size = 45045
user system total real
Niklas1 1.480000 0.010000 1.490000 ( 1.484895)
Niklas2 0.350000 0.000000 0.350000 ( 0.343872)
Marc-André 0.470000 0.010000 0.480000 ( 0.493646)
Cary1 1.890000 0.010000 1.900000 ( 1.895684)
Cary2 0.520000 0.010000 0.530000 ( 0.531843)
n = 13, k = 4, size = 200200
user system total real
Niklas1 4.160000 0.070000 4.230000 ( 4.225072)
Niklas2 1.210000 0.000000 1.210000 ( 1.216814)
Marc-André 2.170000 0.030000 2.200000 ( 2.203629)
Cary1 29.930000 0.580000 30.510000 ( 30.545276)
Cary2 1.720000 0.040000 1.760000 ( 1.757895)
n = 13, k = 5, size = 600600
user system total real
Niklas1 12.750000 0.040000 12.790000 ( 12.800083)
Niklas2 3.070000 0.010000 3.080000 ( 3.085927)
Marc-André 3.630000 0.010000 3.640000 ( 3.637411)
Cary1 191.200000 0.890000 192.090000 (192.319270)
Cary2 5.290000 0.300000 5.590000 ( 5.625138)
n = 16, k = 2, size = 6435
user system total real
Niklas1 2.120000 0.010000 2.130000 ( 2.131065)
Niklas2 0.090000 0.010000 0.100000 ( 0.092635)
Marc-André 0.080000 0.000000 0.080000 ( 0.076312)
Cary1 0.290000 0.000000 0.290000 ( 0.295062)
Cary2 0.070000 0.000000 0.070000 ( 0.071995)
n = 16, k = 3, size = 1009008
user system total real
Niklas1 62.370000 0.940000 63.310000 ( 63.404404)
Niklas2 8.070000 0.020000 8.090000 ( 8.099837)
Marc-André 14.080000 0.330000 14.410000 ( 14.424437)
Cary1 48.930000 0.220000 49.150000 ( 49.227445)
Cary2 13.540000 0.280000 13.820000 ( 13.856880)
n = 16, k = 4, size = 2627625
user system total real
Niklas2 22.530000 0.290000 22.820000 ( 23.252738)
Marc-André 35.850000 1.160000 37.010000 ( 37.159520)
Cary2 39.850000 0.860000 40.710000 ( 40.780489)
n = 18, k = 2, size = 24310
user system total real
Niklas2 0.280000 0.000000 0.280000 ( 0.288286)
Marc-André 0.240000 0.020000 0.260000 ( 0.262669)
Cary2 0.240000 0.010000 0.250000 ( 0.245008)
n = 18, k = 3, size = 2858856
user system total real
Niklas2 37.150000 2.670000 39.820000 ( 48.484321)
Marc-André 68.010000 1.350000 69.360000 ( 70.249403)
Cary2 48.300000 0.840000 49.140000 ( 49.591279)
n = 20, k = 2, size = 92378
user system total real
Niklas2 1.260000 0.000000 1.260000 ( 1.271094)
Marc-André 1.180000 0.040000 1.220000 ( 1.205478)
Cary2 1.210000 0.010000 1.220000 ( 1.232024)
<强>解释强>
我们似乎有一个明显的赢家。恭喜,Marc-André!尼克拉斯,这次没有金牌,但白银也不错。
我会告诉我的代码,让@Niklas和@ Marc-André与他们交谈,因为他们更好地理解他们的代码是如何工作的。当k
的值很小(2或3)时,我的代码似乎工作得很好。然而,随着该参数的增加,我的代码花费了越来越多的时间来抛出重复项(例如,当我已经“拥有”[[2,3],[3,4,5],[6,7]
时解雇[[6,7,[3,4,5][2,3]]
。特别是,请查看{{1}的结果这部分是因为我设计了任意分区的代码,而不仅仅是那些看起来像n = 13, k = 5
的代码。我将看一下我是否可以做任何事情来利用这个结构(不会彻底改变我的代码) ),但我对结果并不乐观。
修改强>
我更新了基准测试,以包含我的第二个解决方案(“cary2”)的结果。它发布了与[m, m,...,m, m+1, m+1,...m+1]
大致相当的解决方案时间,考虑到两种算法都避免了不必要的组合枚举,这并不奇怪。
修改2
我已经更新了基准,以包含@Niklas的第二个解决方案。我把新的“Niklas2”和原来的“Niklas2”贴上了标签。我还为@Marc-André
添加了两个测试。我尝试运行n = 18
(用于“Niklas1”,“Marc-André”和“Cary2”),但是在5分钟左右后取消了它,因为它没有获得初始解决方案。
我相信结果不言而喻。