编辑:现在我认为这是扫描线问题。 (见底部的update2)
在这个问题中,我们给出了N
个对象和M
个约束。 (N
可以是200k
,M
可以是100k
)。每个对象都是黑色或白色。每个约束的格式为(x, y)
,表示在对象范围x..y
中,只有一个白色对象;其余的都是黑色的。我们想确定可以存在的最大白色对象数,或者是否无法满足约束条件。
我观察到如果约束完全包含在另一个约束中,则内部约束将指示可以放置白色对象的位置。此外,如果在另一个中包含多个非交叉约束,则应该是不可能的,因为它违反了每个约束只能有一个白色对象的事实。该算法应该足够快,可以在2-3秒内运行。
更新:其中一个答案提到确切的封面问题;这是一个非NP完全的专门实例吗?
Update2:如果我们将每个约束更改为 begin 和 end 事件,并对这些事件进行排序,我们是否可以系统地扫描这些事件并分配白色对象?< / p>
答案 0 :(得分:2)
你的问题可以表示为exact cover problem:约束区间形成要覆盖的集合,每个白色对象覆盖它所属的那些约束区间。那么,你的问题是找到一个白色物体的子集,它只覆盖每个约束间隔一次。
确切的覆盖问题通常是NP完全的,尽管这显然不一定意味着它们的任何特定子集。但是,仍然存在一些算法,例如Knuth's Algorithm X(由dancing links实现),可以非常有效地解决大多数此类问题。
问题的一维结构可能也允许更直接的专业解决方法。但是,算法X是用于攻击此类问题的非常好的通用工具。 (例如,最快sudoku solvers通常使用类似的东西。)
答案 1 :(得分:1)
是的,有一个(点) - 扫描算法。这个有点不优雅,但我认为它有效。
首先,扫描嵌套间隔。按排序顺序处理开始和结束事件(断路器留给您)并保留一个未知包含另一个间隔的活动间隔列表。要处理begin事件,请附加相应的间隔。要处理结束事件,请检查是否已删除相应的间隔I
。如果没有,请从列表中删除I
以及J
之前的所有剩余时间间隔I
。对于每个此类J
,将两个间隔(其并集是设置差异J \ I
)附加到黑色间隔列表中。
第二,扫除收缩黑暗间隔。换句话说,删除已知为黑色的对象,重新编号,并相应地调整约束。如果整个约束被涂黑,则没有解决方案。
第三,扫描以解决现在非嵌套间隔的问题。贪婪的解决方案可证明是最佳的。
示例:假设我有半开约束[0,4],[1,3],[2,5]。第一次扫描会产生停电[0,1]和[3,4]。第二次扫描留下约束[a,c),[a,c),[b,d)。*贪婪扫描将白色物体放置在新位置a,c,d(旧位置1,4,5)。
第二次扫描的插图:
0 1 2 3 4 5 old coordinates
[ )
[ )
[ )
** ** blackouts
a b c d new coordinates
[ )
[ )
[ )