贪心_NYOJ12

南阳理工acm喷水装置2原题地址:https://blog.csdn.net/a_eagle/article/details/7269591

贪心算法最小区间覆盖问题。

思路,将所有区间按左端点从小到大排序,顺序处理每个区间。在选择某一区间时,先判断区间的左端点是否在已覆盖的区间内,再在满足条件的区间里找到右端点最大的,即能覆盖的区域最多的,若在选择某一区间时所有的可选择区间的左端点都不在已覆盖的区间内,则无答案。

本题首先判断它的喷水区域是否能把草坪的宽度盖满,如果某一装置的喷水区域都不能把宽度占满,就不用考虑此装置。再者就是判断每个喷水装置的有效覆盖区间,得根据它所能覆盖的上边界来判断.

上代码:

/*最小区间覆盖问题*/
#include<bits/stdc++.h>
using namespace std;
typedef struct
{
    double L;
    double R;
}INTERVAL;
bool f(const INTERVAL & a, const INTERVAL & b)
{
    return a.L < b.L;
}
int main(void)
{
    int N;
    cin >> N;
    while(N--)
    {
        int n,w,h;
        cin >> n >> w >> h;
        vector<INTERVAL> v;
        while(n--)
        {
            int x,r;
            INTERVAL t;
            cin >> x >> r;
            double len =(double) r*r -(double)h/2.0*h/2.0;
            if(len < 0)//如果小于0 不考虑
                continue;
            t.L = x - sqrt(len);
            t.R = x + sqrt(len);
            v.push_back(t);
        }
        sort(v.begin(),v.end(),f); //按照左端点进行排序
        int count = 0,flag = 1,i;
        double sum = 0,max = 0;
        while(sum < w)//关键思想
        {
            max = 0;//右端点最大值
            for(i = 0; i < v.size() && v[i].L <= sum; i++)
            {//从左端点能和已覆盖区域相连的区间中找右端点最大的区间
                if((v[i].R - sum) > max)
                {
                    max = v[i].R - sum;
                }
            }
            if(max == 0)//如果等于0就说明在这一区间选择上没有任何区间能和已覆盖区域连起来
            {
                flag = 0;
                break;
            }
            else
            {
                sum += max;//更新已覆盖区域大小
                ++count;
            }
        }
        if(flag == 1)
            printf("%d\n",count);
        else
            printf("0\n");
    }

    return 0;
}

猜你喜欢

转载自www.cnblogs.com/wangweigang/p/9055755.html