给定实直线 $ L $ 上 $ n $ 个开区间组成的集合 $ I $,和一个正整数 $ k $,试设计一个算法,从开区间集合 $ I $ 中选取出开区间集合 $ S \subseteq I $,使得在实直线 $ L $ 的任何一点 $ x $,$ S $ 中包含点 $ x $ 的开区间个数不超过 $ k $。且 $ \sum\limits_{z \in S} | z | $ 达到最大。这样的集合 $ S $ 称为开区间集合 $ I $ 的最长 $ k $ 可重区间集。$ \sum\limits_{z \in S} | z | $ 称为最长 $ k $ 可重区间集的长度。
对于给定的开区间集合 $ I $ 和正整数 $ k $,计算开区间集合 $ I $ 的最长 $ k $ 可重区间集的长度。
建图分析
最长k可重区间集,若将线段看成点,可以看做选择k条不相交路径(因为每个点只能选一次)的权值和最大。
方法1:直接按照朴素的想法建图。
按左端点排序所有区间,把每个区间拆分看做两个顶点<i.a><i.b>,建立附加源S汇T,以及附加顶点S’。
- 连接S到S’一条容量为K,费用为0的有向边。
- 从S’到每个<i.a>连接一条容量为1,费用为0的有向边。
- 从每个<i.b>到T连接一条容量为1,费用为0的有向边。
- 从每个顶点<i.a>到<i.b>连接一条容量为1,费用为区间长度的有向边。
- 对于每个区间i,与它右边的不相交的所有区间j各连一条容量为1,费用为0的有向边。
边数是O(N^2),求最大费用最大流,最大费用流值就是最长k可重区间集的长度。
方法2:改变一下思路,把端点作为网络中的顶点,区间恰恰是特定一些端点之间的边,这样建模的复杂度更小。
离散化所有区间的端点,把每个端点看做一个顶点,建立附加源S汇T。
- 从S到顶点1(最左边顶点)连接一条容量为K,费用为0的有向边。
- 从顶点2N(最右边顶点)到T连接一条容量为K,费用为0的有向边。
- 从顶点i到顶点i+1 $(i+1\le n)$,连接一条容量为无穷大,费用为0的有向边。
- 对于每个区间[a,b],从a对应的顶点i到b对应的顶点j连接一条容量为1,费用为区间长度的有向边。
边数是O(N)。求最大费用最大流,最大费用流值就是最长k可重区间集的长度。
代码
1 |
|