我正在尝试创建一个算法来解决以下问题:
输入是包含整数对(键,值)的集的未排序列表。每对中的第一个在集合中是正面且唯一的。
我想找到一个算法来分割输入集,以便可以对这些集进行排序,使得对于每个键,该值在设置顺序中不会减少。
有一个trival解决方案是将集合分成每个单独的值并对它们进行排序,我希望在分割的集合数量方面更有效。
您遇到过类似的问题和/或建议的技巧吗? 在多项式时间内,最佳(最小分裂数)解决方案听起来是否可能?
编辑:在示例中,“< =”运算符表示对整个集合的约束,其中对于每个键值(100,101,102),相应的值等于或大于先前集合中的值(或从集合中省略)。即,使用输出集中的顺序提取每个键的值,得出:
答案 0 :(得分:0)
我建议使用A*来找到最佳解决方案。从左到右逐步构建拆分集的顺序,最大限度地减少实现此目标所需的集合数。
A *根据总费用的某些启发式估算访问州。我建议 state 由目前已包含在订单中的所有对的总数来描述。如果每个键的所有值都不同,那么您可以通过简单地存储每个键的最后一个值来简明地表示此信息。否则你将不得不以某种方式处理相同的价值,所以你知道哪些已经包括在内,哪些不包括在内。对于每个州,你都会保留一些表示通向它的最佳顺序,但是在状态保持不变的情况下可能会一直更新。
启发式应该是从开始到当前状态到目标的路径总成本的估计值。它可能太低了,但绝不能太高。在我们的例子中,启发式算法应该计算到目前为止订单中包含的(可能是拆分的)集合的数量,并添加仍然等待插入的(未分裂的)集合的数量。由于剩下的集合可能需要拆分,这可能太低了,但是因为你永远不会比那些仍在等待插入的集合少,所以它是一个合适的启发式。
现在您有一些状态的优先级队列,按此启发式的值排序。您从中提取最少的项目,并且知道从队列中提取状态的那一刻,到该状态的成本不能再降低,因此直到该状态的路径是最佳的。现在,您要检查可以从中获得的其他状态:接下来哪些其他对可以按拆分集的顺序排列?对于具有准备包含的对的每个剩余集合,您将创建一个新的后续状态,从该集合中准备好所有对。到目前为止,成本增加了一倍。如果你设法采取一整套,而不进行拆分,那么剩余成本的估算会减少一个。
对于这个新状态,您可以检查它是否已经存在于优先级队列中。如果是,并且其先前的成本高于刚刚计算的成本,则更新其成本以及通向它的最佳路径。确保优先级键相应地改变其位置(“减少键”)。如果之前队列中没有状态,则将其添加到队列中。
考虑一下,这与使用拆分数作为成本运行Dijkstra's algorithm相同。并且由于每个边缘的成本为零或成本为1,因此您可以更轻松地实现此功能,而根本不需要任何优先级队列。相反,您可以使用两个集合,称为S₀
和S₁
,其中来自S 0的所有元素需要相同数量的分割,而来自S 1的所有元素需要多一个分割。用伪代码粗略勾勒出来:
S₀ = ∅ (empty set)
S₁ = ∅
add initial state (no pairs added yet, all sets remain to be added) to S₀
while True
while (S₀ ≠ ∅)
x = take and remove any element from zero
if x is the target state (all pairs included in the order) then
return the path information associated with it
for (r: those sets which remain to be added in state x)
if we can take r as a whole then
let y be the state obtained by taking r as the next set in the order
if y is in S₁, remove it
add y to S₀
else if we can add only some elements from r then
let y bet the state obtained by taking as many elements from r as possible
if y is not in S₀, add it to S₁
S₀ = S₁
S₁ = ∅