目录
模型1
模型描述
有若干个区间,问最少需要多少个点满足每个区间中至少有一个点。
像这样的模型,我们称之为摄像头1模型。
例题
例题:NKOJ P5220 摄像头1(例题被老师隐藏了,该链接可能打不开)
问题描述
有一个监控工程:在一条长度为L的笔直的公路上安装若干个摄像头,用于监控交通状况。我们可以把这条公路看作数轴[0,L]。
何老板承包了这项工程,但交管部门对摄像头的安置提出了n个要求,每个要求形如[x,y],表示在[x,y]这段区间至少要安置一个摄像头。
何老板想要用尽可能少的成本完成这项工程,因此,他想知道,最少需要安装多少个摄像头?
输入格式
第一行,一个整数n,表示有n个要求需要满足。
接下来n行,每行两个整数x和y,表示一个要求,即[x,y]这段区间至少要求一个摄像头。
输出格式
一行,一个整数,表示最少所需摄像头的个数。
样例输入
4
3 6
2 4
0 2
4 7
样例输出
2
提示
1
≤
n
≤
100000
1\le n\le 100000
1≤n≤100000
0
≤
x
≤
y
≤
L
≤
1000000000
0\le x\le y\le L\le 1000000000
0≤x≤y≤L≤1000000000
思路
每个区间都有一个左端点l
和右端点r
。
struct camera{
int l,r;
}c[100005];
我们按右端点从小到大排序:
bool cmp(camera a,camera b){
return a.r < b.r;
}
接下来是重点:
我们先定义一个变量first
,表示最底层的区间(如图):
接下来用for
循环判断,当c[first].r < c[i].l
时,说明该区间与c[first]
区间不再重叠,此时应加装摄像头,并更新first
。
注意:摄像头数量应初始化为1。
for(int i = 0; i < n; i++){
scanf("%d%d",&c[i].l,&c[i].r);
}
sort(c,c+n,cmp);
for(int i = 1; i < n; i++){
if(c[first].r < c[i].l){
ans++;
first = i;
}
}
参考程序
#include<bits/stdc++.h>
using namespace std;
struct camera{
int l,r;
}c[100005];
bool cmp(camera a,camera b){
return a.r < b.r;
}
int main(){
int n,first = 0,ans = 1;
scanf("%d",&n);
for(int i = 0; i < n; i++){
scanf("%d%d",&c[i].l,&c[i].r);
}
sort(c,c+n,cmp);
for(int i = 1; i < n; i++){
if(c[first].r < c[i].l){
ans++;
first = i;
}
}
printf("%d",ans);
return 0;
}
模型2
模型描述
有若干个小区间,最少选择几个小区间可以完全覆盖大区间?
像这样的模型,我们称之为摄像头2模型。
例题
例题:NKOJ P5221 摄像头2(例题被老师隐藏了,该链接可能打不开)
问题描述
NK中学里有一条长度为L的笔直道路,同学们可以把该路看作数轴,路的一段坐标为0,一段坐标为L,表示区间[0,L]
在这条路上安装有n个摄像头,每个摄像头都有一定的拍摄区间,第i个摄像头覆盖的区间为[Xi,Yi]
本着节约用电的态度,何老板想知道,最少开启几个摄像头就可以将整个这条路都置于视频监控中?请你帮他回答。
输入格式
第一行,两个整数n和L
接下来n行,每行两个整数x和y,表示一个摄像头拍摄的区域,即[x,y]这段区间被该摄像头覆盖。
输出格式
一个整数,表示最少所需开启的摄像头个数
如果无解,输出-1
样例输入 1
4 6
3 6
2 4
0 2
4 7
样例输出 1
3
样例输入 2
10 28
5 24
8 27
9 19
3 17
13 18
9 25
19 29
12 15
25 29
0 6
样例输出 2
3
提示
1
≤
n
≤
100000
1\le n\le 100000
1≤n≤100000
1
≤
L
≤
1000000000
1\le L\le 1000000000
1≤L≤1000000000
0
≤
x
≤
y
≤
1000000000
0\le x\le y\le 1000000000
0≤x≤y≤1000000000
样例说明: 选择的摄像头分别覆盖下列区间
[0,2] [2,4] [3,6]
思路
将线段按左端点从小到大排序,如果左端点相同,按右端点从大到小排序。
从左往右依次讨论每条线段,优先选择右端点大的线段。
- 记录目前已选线段中,最远能覆盖的距离
nowfar
。 - 讨论所有左端点<=
nowfar
且未被讨论的线段,记录右端点最大值maxright
。 - 若
maxright
>nowfar
,则nowfar = maxright
。否则无解。
参考程序
#include<bits/stdc++.h>
using namespace std;
int n,l;
struct camera{
int l,r;
}c[100005];
bool cmp(camera a,camera b){
if(a.l == b.l){
return a.r > b.r;
}else{
return a.l < b.l;
}
}
int solve(){
if(c[1].l > 0){
return -1;
}
int ans = 1;
int nowfar = c[1].r;
int maxright = c[1].r;
if(nowfar >= l){
return ans;
}
int i = 2;
while(true){
for(; (i <= n && c[i].l <= nowfar); i++){
maxright = max(maxright,c[i].r);
}
if(maxright <= nowfar){
return -1;
}
ans++;
nowfar = maxright;
if(nowfar >= l){
return ans;
}
}
return -1;
}
int main(){
int tp;
scanf("%d%d",&n,&l);
for(int i = 1; i <= n; i++){
scanf("%d%d",&c[i].l,&c[i].r);
}
sort(c+1,c+n+1,cmp);
tp = solve();
printf("%d",tp);
return 0;
}
模型三
模型描述
有若干个区间,最多选几个区间使它们之间两两不重叠?
像这样的模型,我们称之为摄像头3模型。
例题
例题:NKOJ P5227 摄像头3(例题被老师隐藏了,该链接可能打不开)
问题描述
NK中学里有一条长度为L的笔直道路,同学们可以把该路看作数轴,路的一段坐标为0,一段坐标为L,表示区间[0,L]
在这条路上安装有n个摄像头,每个摄像头都有一定的拍摄区间,第i个摄像头覆盖的区间为
何老板想开启其中k个摄像头,使得这k个摄像头的拍摄区间两两没有交集,问k值最大是多少?
输入格式
第一行为一个正整数 n n n;
在接下来的 n n n行中,每行有 2 2 2个数 a i , b i a_i,b_i ai,bi,描述每条线段。
输出格式
输出一个整数,为 k k k的最大值。
样例输入 1
10
7 8
1 7
0 3
4 9
0 6
5 7
0 3
7 8
7 10
4 7
样例输出 1
3
样例输入 2
10
0 3
1 4
15 19
1 2
1 3
2 5
4 7
2 4
3 8
7 12
样例输出 2
5
提示
对于
20
%
20\%
20%的数据,
n
≤
10
n\le 10
n≤10;
对于
50
%
50\%
50%的数据,
n
≤
1
0
3
n\le 10^3
n≤103;
对于
70
%
70\%
70%的数据,
n
≤
1
0
5
n\le 10^5
n≤105;
对于
100
%
100\%
100%的数据,
n
≤
1
0
6
,
0
≤
a
i
<
b
i
≤
1
0
6
n\le 10^6,0\le a_i < b_i\le 10^6
n≤106,0≤ai<bi≤106。
思路
- 将所有线段的右端点从小到大排序。
- 从左往右讨论每条线段,优先选择左端点大于上条已选线段的右端点,且右端点小的线段。
参考程序
#include<bits/stdc++.h>
using namespace std;
struct camera{
int l,r;
}c[1000005];
bool cmp(camera a,camera b){
return a.r < b.r;
}
int main(){
int n,ans = 1,lastr;
scanf("%d",&n);
for(int i = 0; i < n; i++){
scanf("%d%d",&c[i].l,&c[i].r);
}
sort(c,c+n,cmp);
lastr = c[0].r;
for(int i = 1; i < n; i++){
if(c[i].l >= lastr){
ans++;
lastr = c[i].r;
}
}
printf("%d",ans);
return 0;
}