模型1 : 最小区间覆盖
要总结关于序列贪心的几个模型和相关转化。
给定一个 [1,m] 的区间给出 n 个区间$l_i , r_i $
要求选出最少的区间个数使得 [1,m]整点区间被完全覆盖。
对于100%的数据$1 \leq n \leq 10^5 , 1 \leq l_i,r_i \leq 10^9$
Sol : 对于线段集合按照l排序,而r不管。
设当前覆盖成功的最右边界是nowr,每次只需要在符合左端点在[1,nowr+1]的线段的右端点取一个max来更新nowr即可。
具体实现可以用双指针,设当前排除到的线段编号是j,那么之后选取的线段应该是在j之后,复杂度可以到$\Theta (n log_2 n)$
# includeusing namespace std; const int N=1e5+10; int n,m; struct rec{ int l,r; }a[N]; bool cmp(rec a,rec b){return a.l =m) break; } if (nowr>=m) printf("%d\n",ans); else puts("-1"); return 0; }
最小区间覆盖.cpp
模型2 : 选择不相交区间
有n个区间$[l_i , r_i] $,最多选取多少的区间,他们之间两两不不相交
对于100%的数据 $1 \leq n \leq 10^5 , 1 \leq l_i,r_i \leq 10^9$
Sol : 只需要按照右端点$r_i$递增排序,然后按照从前到后遍历每一条线段,能被加入集合的就被加入(即左端点不和之前选的最后一条线段有交)。
证明:设$r_1 < r_2$ , 证明选择$r_1$比选择$r_2$更优
1. 若$l_1 > l_2$ 此时区间$[l_2, r_2]$被$[l_1,r_1]$包含,所以如果选择区间$[l_2,r_2]$那么可以为后面留出更大的空间。
2. 若 $l_1 < l_2$ 此时区间$[l_2,r_2]$那么可以为后面留出更大的空间。
所以上述贪心策略是正确的。
# includeusing namespace std; const int N=1e5+10; int n,m; struct rec{ int l,r; }a[N]; bool cmp(rec a,rec b){return a.r =last_r) last_r=a[i].r,ans++; printf("%d\n",ans); } return 0; }
HDU-2037 (区间端点可以重复)
模型3 :最少的点覆盖所有的区间
有n个区间$[l_i , r_i] $,求最少选取多少个点使得每个区间内都有点。
对于100%的数据 $1 \leq n \leq 10^5 , 1 \leq l_i,r_i \leq 10^9$
Sol: 按照r排序,每次选的点必然是每条线段的右端点,依次选取。
由于对于每一条不能被之前点覆盖线段上面任意位置放一个点是对该线段本身无影响,
而由于以后线段的右端点都在该线段右端点的右侧,所以放在当前最右端可以尽可能覆盖其他线段,
比其他地方作用效果要么相同,要么更好。
# includeusing namespace std; const int N=1e5+10; struct rec{ int l,r; }a[N]; int n; bool cmp(rec a,rec b){return a.r 最少点覆盖.cpp