我有一个元素列表,每个元素都用类型标识,我需要将列表重新排序为最大化相同类型元素之间的最小距离。 / p>
该套装很小(10至30件),因此表现并不重要。
每种类型的物品数量或类型数量没有限制,数据可以被认为是随机的。
例如,如果我有一个列表:
我想生产类似的东西:
A
,B
,C
,A
,D
,F
,B
,A
,{{ 1}},E
,C
,A
,D
,B
是否有算法来实现这一目标?
-Update -
在交换了一些评论后,我得出了次要目标的定义:
- 更新2 -
关于答案。 有很多有用的答案,虽然没有一个是两个目标的解决方案,特别是第二个目标很棘手。
关于答案的一些想法:
我尝试了Evgeny Kluev,回溯和tobias_k公式的组合,但它需要太多时间才能得到结果。
最后,至少对于我的问题,我认为tobias_k是最合适的算法,因为它的简单性和及时的好结果。可能使用模拟退火可以改善它。
答案 0 :(得分:5)
首先,您还没有明确定义的优化问题。如果你想最大化两个相同类型的项目之间的最小距离,那就很好了。如果你想最大化两个A之间以及两个B和......之间以及两个Z之间的最小距离,那么这个定义并不明确。您如何比较两种解决方案:
您需要明确定义的“好”(或更准确地说,“更好”)。我现在假设该措施是: 最大化同一项目 中任意两项之间的最小距离。
这是一种算法,其最小距离为ceiling(N/n(A))
,其中N
是项目总数,n(A)
是实例A
的项目数,假设A
是最多的。
A1, A2, ... , Ak
,其中n(Ai) >= n(A{i+1})
。L
初始化为空。j
到k
的{{1}},请在1
中尽可能统一地分发Ak
类型的项目。示例:给定问题中的分布,算法产生:
L
答案 1 :(得分:3)
这听起来像一个有趣的问题,所以我试了一下。这是我用Python完成的超简单随机方法:
def optimize(items, quality_function, stop=1000):
no_improvement = 0
best = 0
while no_improvement < stop:
i = random.randint(0, len(items)-1)
j = random.randint(0, len(items)-1)
copy = items[::]
copy[i], copy[j] = copy[j], copy[i]
q = quality_function(copy)
if q > best:
items, best = copy, q
no_improvement = 0
else:
no_improvement += 1
return items
正如评论中已经讨论的那样,真正棘手的部分是质量函数,作为参数传递给优化器。经过一番尝试后,我想出了一个几乎总能产生最佳效果的产品。感谢 pmoleri ,指出如何提高效率。
def quality_maxmindist(items):
s = 0
for item in set(items):
indcs = [i for i in range(len(items)) if items[i] == item]
if len(indcs) > 1:
s += sum(1./(indcs[i+1] - indcs[i]) for i in range(len(indcs)-1))
return 1./s
这里有一些随机结果:
>>> print optimize(items, quality_maxmindist)
['A', 'B', 'C', 'A', 'D', 'E', 'A', 'B', 'F', 'C', 'A', 'D', 'B', 'A']
请注意,传递另一个质量函数,相同的优化器可用于不同的列表重新排列任务,例如,作为一个(相当愚蠢的)随机分拣机。
答案 2 :(得分:3)
这是一种算法,它只能最大化相同类型元素之间的最小距离,并且不会做任何事情。以下列表用作示例:
AAAAA BBBBB CCCC DDDD EEEE FFF GG
对于我们的例子,这给出了:
AB....
AB....
AB....
AB....
AB.
如果我们尝试以相同的顺序用其他集填充剩余的列,则会出现问题:
ABCDE.
ABCDE.
ABCDE.
ABCE..
ABD
最后一个'E'距离第一个'E'只有5个位置。
对于我们的例子,这给出了:
ABFEDC
ABFEDC
ABFEDC
ABGEDC
ABG
回到线性数组我们有:
ABFEDCABFEDCABFEDCABGEDCABG
这是尝试对此问题使用模拟退火(C源):http://ideone.com/OGkkc。
答案 3 :(得分:0)
我相信你可以看到你的问题就像一堆物理排斥彼此的粒子。你可以迭代到一个稳定的&#39;情况。
基本伪代码:
force( x, y ) = 0 if x.type==y.type
1/distance(x,y) otherwise
nextposition( x, force ) = coined?(x) => same
else => x + force
notconverged(row,newrow) = // simplistically
row!=newrow
row=[a,b,a,b,b,b,a,e];
newrow=nextposition(row);
while( notconverged(row,newrow) )
newrow=nextposition(row);
我不知道它是否收敛,但这是一个想法:)
答案 4 :(得分:0)
我确信可能有更有效的解决方案,但这是您的一种可能性:
首先,请注意,很容易找到一个产生最小距离之间相同类型的1的排序。只需使用任何随机排序,MDBIOST将至少为1,如果不多了。
因此,首先假设MDBIOST为2.根据MDBIOST为2 的假设,对可能的排序空间进行递归搜索,。您可以使用许多条件来修剪此搜索中的分支。如果您发现有效的订单,请终止搜索。
如果你发现一个有效,请再试一次,假设MDBIOST为3.然后4 ......依此类推,直到搜索失败。
更新:以高号码开头实际上会更好,因为这会更多地限制可能的选择。然后逐渐减少数量,直到找到有效的顺序。
答案 5 :(得分:0)
这是另一种方法。
如果每个项目必须与相同类型的其他项目保持至少k个位置,则从左向右记下项目,跟踪每种类型剩余的项目数量。在每个点放下一个剩下最多的物品,你可以合法放下。
如果没有超过相同类型的ceil(N / k)项目,这将适用于N个项目,因为它将保留此属性 - 在放下k个项目之后我们减少k个项目并且我们放下了每种类型中至少有一种以ceil(N / k)类型的物品开始。
考虑到一系列混合物品,你可以计算出你能支持的最大k,然后列出要解决这个问题的物品。