本节记录了贪心算法的三类区间问题:互不相交,区间覆盖,区间选点。按照自己的思路进行了一定的解析。较为简单,不说废话了。
问题:有n个需要在同一天使用同一个教室的活动a1,a2,…,an,教室同一时刻只能由一个活动使用。每个活动ai都有一个开始时间si和结束时间fi 。一旦被选择后,活动ai就占据半开时间区间[si,fi)。如果[si,fi]和[sj,fj]互不重叠,ai和aj两个活动就可以被安排在这一天。
该问题就是要安排这些活动使得尽量多的活动能不冲突的举行。
(1) 依据贪心思想,每次选取最优结果,倘若每次从未举办的活动中选取活动结束时间最早的活动来举办,是否意味着在24内就能尽可能多的举办活动呢?
(2) 将数组按结束时间排序,在选择时还要确保下次开始时间大于等于本次结束时间
#include
using namespace std;
#define Max 10//最多活动个数
int main(){
int i,j,temp;//循环用
int n;//活动个数
int arry[Max][2];
int sum;//活动个数
int s=0,e=24;//一天24个小时【0,24】
cin>>n;
for(i=0;i>arry[i][0]>>arry[i][1];
}
//冒泡排序:升序
//按结束时间排序
for (i = 0; i < n; i++){
for (j = i + 1; j < n; j++){
if (arry[i][1]> arry[j][1]){
temp=arry[i][1];
arry[i][1]=arry[j][1];
arry[j][1]=temp;
//整组交换
temp=arry[i][0];
arry[i][0]=arry[j][0];
arry[j][0]=temp;
}
}
}
//初始化赋值
temp=arry[0][1];
cout<<"["<24 || arry[i][0]>24)
//break;
}
cout<
测试用例:5 ;
【2,10)【5,6)【11,13)【13,20)【19,24);
问题:给定一个长度为m的区间,再给出n条线段的起点和终点(注意这里是闭区间),
求最少使用多少条线段可以将整个区间完全覆盖
(1) 既然是完全覆盖,那么必定不存在相邻区间不相交的情况,也就是相邻区间必定是相交的。比如:【1,3】【4,5】【5,6】三条区间是不可能覆盖区间【1,6】
(2) 这里所说的相邻区间指的是按左端点排序以后的各个区间。比如【1,4】【5,6】【3,5】,不能说【1,4】与【5,6】是相邻区间不相交的情况,因为先排序得到【1,4】【3,5】【5,6】所以该组三个区间不存在相邻区间不相交的情况。
(3) 比较麻烦的是下面这种情况,你需要在【3,6】【2,7】之间做一个选择:
(4) 因为要选择最少的区间个数,所以应该选【2,7】。如何选择【3,6】【2,7】?循环与【1,4】相交的区间从中找出右端点最大的即可,这也是这段程序复杂的地方。
#include
using namespace std;
#define Max 10
int main(){
int i,j,temp,k;//循环用
int n;
int m;
int arry[Max][2];
int sum;//总数
int start,end;
cout<<"总区间长度:";cin>>m;
cout<<"线段条数:";cin>>n;
for(i=0;i>arry[i][0]>>arry[i][1];
}
//冒泡排序:升序
//左端点从小到大排
for (i = 0; i < n; i++){
for (j = i + 1; j < n; j++){
if (arry[i][0]> arry[j][0]){
temp=arry[i][0];
arry[i][0]=arry[j][0];
arry[j][0]=temp;
//整组交换
temp=arry[i][1];
arry[i][1]=arry[j][1];
arry[j][1]=temp;
}
}
}
//主要的逻辑计算
//第一个必选
sum=1;
i=0;
start=arry[0][0];
end=arry[0][1];
cout<<"("<end && arry[j][0]<=end && arry[j][1]>=endM){//相交
endM=arry[j][1];
i=j;
}
else{
break;
}
}
sum++;
end=arry[i][1];//更新end的数值
cout<<"("<
(3) 至少需要1个雷达,才能覆盖A,B岛
(4) 至少需要1个雷达,才能覆盖A,B岛
D是用来确定该岛屿能被雷达扫射到的区间,此处直接给出该区间,免去数学计算。
#include
using namespace std;
#define Max 10
int main(){
int i, j, temp;//循环用
int n,sum;
int arry[Max][2];
int start, end;//区间开始的点和区间结束的点
cin >> n;
for (i = 0; i < n; i++){
cin >> arry[i][0] >> arry[i][1];
}
//冒泡排序:升序
//按左点从小到大排序
for (i = 0; i < n; i++){
for (j = i + 1; j < n; j++){
if (arry[i][0]> arry[j][0]){
temp = arry[i][0];
arry[i][0] = arry[j][0];
arry[j][0] = temp;
//整组交换
temp = arry[i][1];
arry[i][1] = arry[j][1];
arry[j][1] = temp;
}
}
}
//分析
start = arry[0][0];
end = arry[0][1];
sum = 1;//sum是雷达个数,最少一个
for (i = 1; i < n;i++){
if (start<=arry[i][0] &&end>=arry[i][1]){//区间包含
start = arry[i][0]; end=arry[i][1];
}
else if (end>arry[i][0] && end<=arry[i][1]){//区间相交
start = arry[i][0];
}
else if (end<=arry[i][0]){//区间交集为空
cout << "(" << start << "," << end << ")" << endl;//输出,可以不看
sum++;
start = arry[i][0];
end = arry[i][1];
}
}
cout << "(" << start << "," << end << ")" << endl;//输出,可以不看
cout << "最少雷达=" << sum;
return 0;
}
测试用例A:5 ;
(2,5)(6,9)(8,11)(10,11)(9,15)
测试用例B:4 ;
(1,5)(2,7)(3,5)(6,10)
比较有疑虑的地方在于,没有找到对应题目所在的网址,也就是代码没有AC过,所以我尽量编写测试用例来测试代码的准确性,目前没有发现不合理的地方。一方面要照顾输出的格式,另一方面也是为了方便读者理解,代码有一些可以优化和简洁的地方就没有做了。