一种简单但是很费时间的贪心题模板


区间合并


给定 n 个区间 [li,ri],要求合并所有有交集的区间。

注意如果在端点处相交,也算有交集。

输出合并完成后的区间个数。

例如:[1,3] 和 [2,6] 可以合并为一个区间[1,6]。

输入格式

第一行包含整数 n。

接下来 n 行,每行包含两个整数 l 和 r。

输出格式

共一行,包含一个整数,表示合并区间完成后的区间个数。

数据范围

1≤n≤100000,
−109≤li≤ri≤109

输入样例:

5
1 2
2 4
5 6
7 8
7 9

输出样例:

3

题目的意思比较简单,就是有一些区间,给你他的起始点和终止点,让你将遇到的小区间合并成一个大区间,并最终返回大区间的个数。

思路一般是先将这些起始点和终点按照起始点有小到大排序,如果遇到起始点相同的,就排序他的终点,终点也是有小到大进行排序,这样可以省去一些麻烦。

思路比较简单,但是实现起来有一些细节要注意一下:

算了,先上代码:

#include 

using namespace std ;

const int N = 100010 ; 

struct region
{
    int start ; 
    int end ; 
} re[N]; 

int main()
{
    int n ; 
    cin >> n  ; 
    
    for(int i = 1 ; i <= n ; ++ i )
    {
        cin >> re[i].start >> re[i].end ;
    }
    
    sort(re + 1  , re + n + 1 , [] (region x , region y)
         {
             if(x.start == y.start)
             {
                 return x.end < y.end ; 
             }
             return x.start < y.start ; 
         }) ; 
    
    re[n+1].start = re[n].end + 1  ;  //个人觉得比较妙的一步,他直接限制了下面的for循环必须是if结尾的,就省去了一些麻烦
    
    int start = re[1].start  ; 
    int end = re[1].end ; 
    int num =  1  ; 
    
    for(int i = 2 ; i <= n + 1 ; ++ i)
    {
         if(re[i].start > end)
        {
            num ++ ; 
            start = re[i].start ; 
            end = re[i].end ; 
        }
        else
        {
            end = max(end , re[i].end) ; 
        }
    }
    
    cout << num << endl ; 
    
    return  0;  
}

同理,我们再来看与她极其相似的一道题

校门外的树


某校大门外长度为 L 的马路上有一排树,每两棵相邻的树之间的间隔都是 1 米。

我们可以把马路看成一个数轴,马路的一端在数轴 0 的位置,另一端在 L 的位置;数轴上的每个整数点,即0,1,2,……,L,都种有一棵树。

由于马路上有一些区域要用来建地铁。

这些区域用它们在数轴上的起始点和终止点表示。

已知任一区域的起始点和终止点的坐标都是整数,区域之间可能有重合的部分。

现在要把这些区域中的树(包括区域端点处的两棵树)移走。

你的任务是计算将这些树都移走后,马路上还有多少棵树。

输入格式

输入文件的第一行有两个整数 L和 M,L 代表马路的长度,M 代表区域的数目,L 和 M 之间用一个空格隔开。

接下来的 M 行每行包含两个不同的整数,用一个空格隔开,表示一个区域的起始点和终止点的坐标。

输出格式

输出文件包括一行,这一行只包含一个整数,表示马路上剩余的树的数目。

数据范围

1≤L≤10000,
1≤M≤100

输入样例:

500 3
150 300
100 200
470 471

输出样例:

298

这一题我一开始没仔细看题目,就直接盯着样例看了老半天。

我一开始想的是,这一共500棵树,我怎么算都是297呀,为什么是298呢???

原来是,0-500…….哈哈,那没事了。

所以一共是501棵树。

思路与上题几乎一样

#include 

using namespace std ;

const int N = 110 ; 

struct region
{
    int start  ; 
    int end ; 
} re[N]; 


int main()
{
    int n , m  ; 
    cin >> n >> m ; 
    n ++ ;
    
    for(int i = 1 ; i <= m ; ++ i)
    {
          cin >> re[i].start >> re[i].end ;   
    }
    
    sort(re + 1 , re + 1 + m , [] (region x , region y)
         {
             if(x.start == y.start)
             {
                 return x.end < y.end ; 
             }
             return x.start < y.start ; 
         }) ; 
    
    re[m+1].start = 10001 ; //将x
    
    int start  = re[1].start ; 
    int end = re[1].end ; 
    
    int res = 0 ; 
    
    for(int i = 2 ; i <= m + 1 ; ++ i)
    {
        if(re[i].start > end)
        {
            res += (end - start + 1) ; 
            start = re[i].start ; 
            end = re[i].end ; 
        }
        else
        {
            end = max(end , re[i].end) ; 
        }
    }
    cout << n - res << endl ; 
    return  0 ; 
}

文章作者: 罗林
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 罗林 !
  目录