贪心法:区间完全覆盖问题

问题:区间完全覆盖问题
问题描述:给定一个长度为m的区间,再给出n个区间的起点和终点,求最少使用多少个区间可以将整个区间完全覆盖。
方法:
• 先将n个区间按照起点进行递增排序。
• 令s表示已经覆盖到的区域。再剩下的区间中找出所有左端点小于等于当前已经覆盖到的区域s并且右端点大于等于s的区间,取右端点最大的区间加入,直到已经覆盖全部的区域。
举例:
m为10
N = 7:[1,5]、[1,6]、[3,6]、[1,7]、[6,9]、[9,10]、[7,9]。
步骤:
1.先将N按照左端点递增进行排序,得到:[1,5]、[1,6]、[1,7]、[3,6]、[6,9]、[7,9]、[9,10]
2.然后取第一个区间为[1,7],因为7是从1开始最远的区间右端点,s变成7。
3.然后从接下来的区间中找左端点小于等于7,并且右端点大于等于7的区间,有[6,9]、[7,9]。则取[7,9],s变成9
4…然后从接下来的区间中找左端点小于等于9,并且右端点大于等于9的区间,有[9,10],只有选它,并且覆盖成功,结果为3。
#include
#include
using namespace std;
const int maxn = 1000;
int N, T;
struct Interval{
int start, end;
}a[maxn], result[maxn];

int cmp(const Interval &a, const Interval &b)
{
if(a.start < b.start) return 1;
else if(a.start == b.start && a.end < b.end) return 1;
else return 0;
}

void solve()
{
sort(a, a+N, cmp);
int count = 0;
int s, e = 1;
int i, index = 0;
int ok = 1;
while(e < T)
{
s = e;//更新覆盖区域
for(i=index; i<N; i++)
{
if(a[i].start <= s)
{
if(a[i].end >= s)
{
e = a[i].end;//取符合条件的最远区间。
}
}
else{
index = i;//不符合条件则需要换区间
break;
}
}
if(s >= e)
{
ok = 0;
break;
}
else{
result[count]=a[i-1];
count ++;
}
}
if(ok) printf("%d\n", count);
else printf("-1\n");
for(int k=0; k<count; k++)
{ printf("[%d, %d]\n", result[k].start,result[k].end); }
}
int main()
{
scanf("%d%d",&N,&T);
for(int i=0; i<N; i++)
{
scanf("%d%d",&a[i].start, &a[i].end);
}
solve();
return 0;
}

完全区间覆盖问题
#include
#include
using namespace std;
const int maxn = 1000;
int N, T;
struct Interval{
int start, end;
}a[maxn], result[maxn];

int cmp(const Interval &a, const Interval &b)
{
if(a.start < b.start) return 1;
else if(a.start == b.start && a.end < b.end) return 1;
else return 0;
}

void solve()
{
int count = 0;
int s, e = 1;
int i,index = 0;
s=e;
for(i=index; i<N; i++)
{
if(a[i].start <= s)
{
if(a[i].end >= s)
{
e = a[i].end;//取符合条件的最远区间。
}
}
else{
index = i;//不符合条件则需要换区间
result[count]=a[i-1];
count ++;
s=e;
}
}
if(index==N-1){
result[count]=a[i-1];
count ++;
}
if(count) printf("%d\n", count);
else printf("-1\n");
for(int k=0; k<count; k++)
{ printf("[%d, %d]\n", result[k].start,result[k].end);}
}
int main()
{
scanf("%d",&N);
for(int i=0; i<N; i++)
{
scanf("%d%d",&a[i].start, &a[i].end);
}
sort(a, a+N, cmp);
for(int i=0; i<N; i++)
{
printf("%d %d ",a[i].start, a[i].end);
}
solve();
return 0;
}

数轴上有n个闭区间[ai, bi],选择尽量少的区间覆盖一条指定线段[s, t]。
用贪心法解决这个问题的思路如下:
(1)找到所有的、起点小于s的区间
(2)把这些区间按照起点,从小到大排序
(3)选择终点最大的那个区间,设这个最大的终点是bi
(4)现在问题变成了,“选择尽量少的区间覆盖一条指定线段[bi, t]”
思路:把喷水装置的覆盖范围转化为一段区间,然后问题变成区间完全覆盖问题

#include <stdio.h>
#include <math.h>
#include
using std::sort;
struct node{
double le, ri;
}s[1005];
int cmp(node a, node b)
{
return a.le < b.le;
}
int main()
{
int n, t;
double w, h;
scanf("%d", &t);
while(t --){
scanf("%d%lf%lf", &n, &w, &h);
h /= 2; //要除去2
int i, j;
double temp, r;
for(i = 0, j = 0; i < n; i ++){
scanf("%lf%lf", &temp, &r);
if(r <= h) continue;//如果不能,喷洒到俩边或刚好喷洒到两边
else{
double temp1 = sqrt(rr-hh);//求最长能够形成矩形的宽度
s[j].le = temp -temp1;//左边界
s[j++].ri = temp+temp1;//右边界
}
}
sort(s, s+j, cmp);//排序
// for(i = 0; i < j; i ++){
// printf("%lf %lf…\n", s[i].le, s[i].ri);
// }
if(s[0].le > 0) {printf(“0\n”); continue;} //如果第一个要大于0, 就是0到不了,直接输出0
double end = 0;
i = 0;
int cou = 0;
while(end <= w&&i < j&&cou <= n){//区间覆盖核心代码这里的
temp = end;
while(s[i].le <= end&&i <j ){
if(s[i].ri > temp) temp = s[i].ri;
i++;
}
end = temp+0.000001;//每次都只加上0.00001,俩区间有断点,就能区分
++cou;
}
if(end < w||cou > n){//如果cou>n 就说明有断点, end<w说明到达不了w
printf(“0\n”);
}
else{
printf("%d\n", cou);
}
}
return 0;
}

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值