uva10382(贪心算法---区间覆盖问题)

https://vjudge.net/problem/UVA-10382(uva10382 点击打开题目链接)

区间覆盖问题:数轴上有n个闭区间【a-i,b-i】(i是下标),选择尽量少的区间覆盖一条指定线段【s,t】。

思路:转化成草坪矩形上边界(或下边界)的区间覆盖问题。

分析:因为圆的圆心都在草坪中间,所以如果能覆盖矩形的上边界,就一定能覆盖矩形的下边界。每个圆形洒水器的洒水范围(即n个闭区间)可以通过勾股定理求得,因此就转化为了在矩形上边界这条线段(长度为l)上的区间覆盖问题。
(算法竞赛入门经典)该类题的突破口仍然是区间包含和排序扫描,不过要先进行一次预处理。每个区间在【s,t】外的部分都应该先被切掉,因为他们的存在是毫无意义的。预处理后,在相互包含的情况下,小区间显然不应该考虑。(明白是明白了,不过具体到题目就不清楚怎么预处理了)。
把各区间按照a(区间左侧端点)从小到大排序。如果区间1的左端点大于s,无解(因为其他区间的起点更大,不可能覆盖到s点),否则选择起点小于s的最长区间(至于怎么选择最长区间,这道题就卡在这儿了,看了好多题解代码,最后终于理解的差不多了)。选择此区间【a-i,b-i】后,新的起点应该设置为b-i,并且忽略所有区间在b-i之前的部分,就像预处理一样。

代码:

#include <iostream>
#include <string>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <vector>
#include <cstdio>
#include <map>
#include <cstdlib>
#define pi 2*acos(0)
using namespace std;

const int maxn = 10000 + 10;

struct node
{
    double l,r;
    node(double ll,double rr):l(ll),r(rr){}
    bool operator < (const node x)const//重载小于运算符,进行排序(该题是按照左侧端点从小到大排序,有时候也按照右侧端点排序)
    {
        return l < x.l;
    }
};

vector<node> v;

int main()
{
    int n;
    double l,w;
    while(~scanf("%d%lf%lf",&n,&l,&w))
    {
        v.clear();//清空很重要
        int a,b;
        for(int i = 0;i < n;i++)
        {
            scanf("%d%d",&a,&b);
            if(b * 2.0 <= w)//特例判断,如果整个圆都在矩形里面,一定不选
                continue;
            double p = sqrt((b*1.0)*(b*1.0) - (w/2.0)*(w/2.0));//勾股定理,求出半个区间长度,这里结合图形好好理解,如果理解不了,就做不出题目来。
            v.push_back(node(a - p,a + p));//将区间长度存入容器
        }

        sort(v.begin(),v.end());//切记:排序!!!
        int ans = 1;
        double sl = 0.0,sr = 0.0;

//之前看的代码有这一部分,去掉之后仍然ac,因为下面的循环包含了这种情况
//        if(v.empty() || v[0].l > 0.0)
//        {
//            printf("-1\n");
//            continue;
//        }


        for(int i = 0;i < v.size();i++)
        {
            if(v[i].l <= sl)//左侧的点比左界限小,但是要选一个最长的区间
            {
            //如果有多组数据,都满足左侧点比左界限小,那就一直更新右界限,选择最大的区间。
                sr = max(sr,v[i].r);
            }
            else
            {
            //直到左侧的点比左界限大了,计数加一
                ans++;
                sl = sr;//新的起点(或者需要维护的点)设置为‘b-i’(即sr).
                if(v[i].l > sl)//如果新的区间左侧端点大于起点,不符合情况,跳出循环
                    break;
                sr = v[i].r;//否则,更新右边界
            }

            if(sr >= l)
                break;
        }

        if(sr >= l)
            printf("%d\n",ans);

        else
            printf("-1\n");
    }
    return 0;
}
  • 贪心—区间覆盖,还差的很远啊,继续加油吧。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值