1. 程式人生 > >「一本通 1.1 例 3」噴水裝置

「一本通 1.1 例 3」噴水裝置

題目傳送門
這題看似是圓的覆蓋問題,其實我們可以轉換成圓的左座標和右座標,轉換成矩形覆蓋問題。

貪心策略:

按左端點從小到大排序,每次遍歷一遍,找到符合當前既能覆蓋左端點的,又能離右端點的最遠的點。

#include <bits/stdc++.h>
#define _for(i,a,n) for(int i=a;i<n;++i)
#define rep(i,a,n)for(int i=a;i<=n;++i)
#define input() int T;cin>>T;while(T--)
#define close() ios::sync_with_stdio(false);cin.tie(0);cout.tie(0)
typedef long long ll;
template<class T>inline void read(T &x){bool Finish_read=0;x=0;int f=1;char ch=getchar();while(!isdigit(ch)){if(ch=='-')f=-1;if(ch==EOF)return;ch=getchar();}while(isdigit(ch))x=x*10+ch-'0',ch=getchar();x*=f;Finish_read=1;}
template<class T>inline void print(T x){if(x/10!=0)print(x/10);putchar(x%10+'0');}
template<class T>inline void writeln(T x){if(x<0)putchar('-');x=abs(x);print(x);putchar('\n');}
template<class T>inline void write(T x){if(x<0)putchar('-');x=abs(x);print(x);}
using namespace std;
const int maxn = 15000;
struct node {
    double l, r;
    inline bool operator < (const node &b) const {
        return l < b.l;
    }
}arr[maxn + 5];

int main()
{
    int T;
    double n, x, r, L, W;
    read(T);
    while(T--) {
        read(n), read(L), read(W);
        int tot = 0;
        _for(i, 0 , n) {
            read(x), read(r);
            if(r * 2 <= W) continue;
            arr[++tot].l = x - sqrt(r * r - W * W / 4.0);
            arr[tot].r = x + sqrt(r * r - W * W / 4.0);
        }
        sort(arr + 1, arr + tot + 1);
        double st = 0;
        int ans = 0;
        while(st < L) {
            ans++;
            double tmp = st;
            for(int id = 1; arr[id].l <= tmp && id <= tot; ++id) 
                st = max(st, arr[id].r);
            if(st == tmp && st < L) {
                ans = -1;
                break;
            }
        }
        cout << ans << endl;
    }
    return 0;
}