求出最多可以选择多少条不相交的线段
问题一:
给n条线段,求出最多有多少条线段互不相交。
思路:
这是一个经典问题。具体做法是贪心,也可以使用dp。
贪心做法:按右端点排序,能选就选,不能就不选。因为如果不能选的话,它的加入一定会导致至少一条线段的退出,并且还使得当前线段集的最右端点右移了,一定不优。
dp做法:f[i]表示坐标到i最多选多少条,枚举以i为起点的线段进行转移即可,可能需要进行离散化。
问题二:
给n条线段,线段可以平移,只需要满足右端点不超过一个值即可,当然左端点不能小于0,问最多有多少条线段互不相交。
思路:
这道题我们真的争论了很久,最后给出了一个nlog的贪心做法。而我自己想出来的是一个n^2时空的很臃肿的dp,但原题数据时1e4,所以应该也是合法的。
先得到一些显而易见的推论:线段之间一定不能有空隙,因为如果有空隙一定可以将右面的向左移而不会更劣。如果按右端点递增为他们排序,那么最终的方案中线段编号一定是递增的,因为如果不是递增的,交换逆序的两条线段一定不会更劣。
贪心做法:按右端点排序,对当前的已选择的线段集维护一个返回长度最大值的堆,依次枚举每一条线段,如果直接加到当前线段集的末尾可以,那么就加进去,如果不可以,比较它和堆顶线段的长度,留下一个长度比较短的,扫一遍答案就出来了。这用到了上面的两个结论。
这是一种"可反悔的贪心",值得学习。
dp做法:按右端点排序,f[i][j]表示到坐标i时,最后一条线段编号为j时最多选多少条,先考虑暴力n^3的方法,就是对于每个j枚举后面所有的线段进行转移,考虑优化,我们发现转移到f[j][k]的情况,事实上是f[i][1~k-1]转移的,所以我们只需要维护一个前缀的最大值就可以实现O1的转移。需要注意这种方法不能进行离散化,也就是如果坐标范围很大是无法使用的,因为我们没办法求出所有线段长度可以组合出的长度并将其离散化。
这种通过记录前缀最大值的方式优化一维dp的方法应该是具有普遍意义的,需要掌握。