找到最大的间隔子集

时间:2012-05-31 16:19:30

标签: algorithm puzzle

我试图解决这个问题here

此外,发布问题:您将获得N个间隔的列表。 挑战是选择最大的间隔子集,使得子集中没有三个间隔共享一个公共点?

但无法解决问题。这是我到目前为止所尝试的:

  1. DP:不要认为问题有重叠的子问题,所以这不起作用
  2. 将其缩小为图形,每个点都是一个顶点,而间隔是无向图的边缘。然后问题减少到在图中找到最大长度不相交路径。
  3. 无法想出一个简洁的方法
  4. 尝试将其减少到网络流量但是效果不佳。
  5. 你们可以给我一些关于如何解决这个问题的提示,或者我是否遗漏了什么。对不起,我在很长一段时间后都在做算法,最近一直没见。

2 个答案:

答案 0 :(得分:3)

我会在没有编程的情况下给出解决方案。

让我们将段表示为s 1 ,s 2 ,...,s n 。它们的开头为b 1 ,b 2 ,... b n ,它们的结尾为e 1 , e 2 ,... e n

按段开头对段进行排序,因此b 1 < B'的子> 2 < ...< B'的子>名词。如果没有三个段覆盖一个点的条件成立,则足以检查它们。我们将按照从b 1 到b n 的顺序进行。所以,从b 1 开始,移动到下一个点,依此类推,直到某个点b i 有三个段覆盖它。这些将是段s i 和另外两个,假设s j 和s k 。在这三个段中删除具有最大终点的段,即max {e i ,e j ,e k }。移到下一个段的开头(b i + 1 )。当我们到达b n 时,过程就完成了。剩下的所有段构成了段的最大子集,因此没有三个段共享一个公共点。

为什么这将是最大子集。假设我们的解决方案是S(段的集合)。假设存在最优解S *。再次,按S开头的坐标对S和S *中的线段进行排序。现在,我们将浏览S和S *中的段并比较它们的终点。通过在S中对任何k th 段构造S,其末端坐标小于S *中的k th 段的末端坐标(e k &LT; = E <子>ķ )。因此,S中的段数不小于S (在S *中移动我们总是超越S)。

如果这还不够令人信服,那么首先尝试考虑一个更简单的问题,其中没有两个段可以重叠。解决方案是相同的,但它更直观地看出为什么它给出了正确的答案。

答案 1 :(得分:2)

Shafa是对的;

#include <iostream>
#include <set>

using namespace std;

class Interval{
public:
int begin;int end;
Interval(){
    begin=0;end=0;
}

Interval(int _b,int _e){
    begin=_b;end=_e;
}

 bool operator==(const Interval& i) const {
     return (begin==i.begin)&&(end==i.end);
 }

 bool operator<(const Interval& i) const {
     return begin<i.begin;
 }
};

int n,t,a,b;
multiset<Interval> inters;
multiset<int> iends;

multiset<Interval>::iterator it1;
multiset<int>::iterator et1;

int main(){
scanf("%d",&t);
while(t--){
    inters.clear();
    iends.clear();
    scanf("%d",&n);
    while(n--){
        scanf("%d %d",&a,&b);
        Interval inter(a,b);
        inters.insert(inter);
    }
    it1=inters.begin();
    while(it1!=inters.end()){
        iends.insert(it1->end);
        et1=iends.lower_bound(it1->begin);
        multiset<int>::iterator t=et1;
        if((++et1!=iends.end())&&(++et1!=iends.end())){
            //把剩下的线段全部删掉
            while(et1!=iends.end()){
                multiset<int>::iterator te=et1;
                et1++;
                iends.erase(te);
            }
        }
        it1++;
    }
    printf("%d\n",iends.size());
}
system("pause");
return 0;
}