Week3 作业 C

题目描述:

数轴上有 n (1<=n<=25000)个闭区间 [ai, bi],选择尽量少的区间覆盖一条指定线段 [1, t]( 1<=t<=1,000,000)。
覆盖整点,即(1,2)+(3,4)可以覆盖(1,4)。
不可能办到输出-1

思路:

按顺序贪最长有效长度;

直观上来说,选一个区间,一定要让其最大有效长度最大,那么如何判断一个区间的有效长度?假设已经选了i个区间,当选择第i+1区间时,要看第i+1个区间里有多少长度没有被覆盖,这也就是第i+1个区间的有效长度,如果选第i+1个区间时,从左端点到右端点搜索,则时间复杂度是O(n^n);为了在选择时,不对后序的选择产生影响,我们对左端点进行排序,这样就可以顺序的用O(n)的时间遍历所有区间

正确性证明:

假设已经选了k个区间,其覆盖范围是从L到R(假设L>1),则接下来需要选择的区间一定有左端点在[1,L]之间的,假设我们又选择了一个区间,其左端点是LL(1<LL<L),则接下来仍然要选择左端点在[1,LL]之间的区间,依次类推,则一定要选择开头是1的区间;而如果按顺序从1开始选择区间,因为每次选的是有效长度最大的,所以第一个选的区间不会比最优解中从1开始的那个区间的覆盖长度短;假设选了[1,RR],则把RR+1相当于是1,继续重复上述推证,可得到这种方法的解不会比最优解差。

总结:

贪心往往和排序相联系

代码:

 1 //贪最长有效长度,按顺序贪,假设已经选了[1,K],下一步一定要选一个起点在[2,K+1]之内的区间,每个区间都有一个有效长度,max_就是这些区间的最长有效长度
 2 #include <cstdio>
 3 #include <iostream>
 4 #include <algorithm>
 5 using namespace std;
 6 struct sec
 7 {
 8     int l,r,len;  //区间的起点,终点和长度 
 9     bool operator< (const sec &x) const
10     {
11         if(l!=x.l) return l<x.l;    //左端点升序,长度降序 
12         else if(len!=x.len) return len>x.len;
13     }
14 }a[100005]; 
15 int main()
16 {
17     int n,t; cin>>n>>t;
18     for(int i=1;i<=n;i++)
19         scanf("%d %d",&a[i].l,&a[i].r),
20         a[i].len=a[i].r-a[i].l;
21     sort(a+1,a+n+1);
22     int end=0,oldEnd=0,i=1,ans=0;
23     while( end<t )
24     {
25         int max_=0; 
26         i--;
27         while(1)
28         {
29             i++;
30             if( a[i].l<=end+1 )  //计算有效长度
31             {
32                 if( a[i].r-end> max_) max_=a[i].r-end;
33             }         
34             else break;   //当break时,i加到了下次的位置,所以上方i--,并设i的初始值是1 
35         }
36         if(max_==0)
37         {
38             cout<<-1<<endl;
39             return 0;
40         }
41         end=end+max_;
42         ans++;
43     }
44     cout<<ans<<endl;
45 } 
原文地址:https://www.cnblogs.com/qingoba/p/12535226.html