​http://nyoj.top/problem/12​

  • 内存限制:64MB 时间限制:3000ms

题目描述:

有一块草坪,横向长w,纵向长为h,在它的橫向中心线上不同位置处装有n(n<=10000)个点状的喷水装置,每个喷水装置i喷水的效果是让以它为中心半径为Ri的圆都被润湿。请在给出的喷水装置中选择尽量少的喷水装置,把整个草坪全部润湿。

输入描述:

第一行输入一个正整数N表示共有n次测试数据。
每一组测试数据的第一行有三个整数n,w,h,n表示共有n个喷水装置,w表示草坪的横向长度,h表示草坪的纵向长度。
随后的n行,都有两个整数xi和ri,xi表示第i个喷水装置的的横坐标(最左边为0),ri表示该喷水装置能覆盖的圆的半径。

输出描述:

每组测试数据输出一个正整数,表示共需要多少个喷水装置,每个输出单独占一行。
如果不存在一种能够把整个草坪湿润的方案,请输出0。

样例输入:


2
2 8 6
1 1
4 5
2 10 6
4 5
6 5


样例输出:


1
2


解题思路:

因为所有的喷水装置都在横向中心线上,所以可以利用圆与草坪边界的交点来转换成区间覆盖问题.主要思路就是在既能够保证两点有公共区域的情况下又能保证能够往右覆盖的面积最大,也就是右交点最大.

#include <cmath>
#include <iostream>
#include <algorithm>
using namespace std;
struct edge {
double l, r;
}e[10010];
int cmp(edge a, edge b) {
return a.l < b.l;
}
int main()
{
double l, temp, maxn;
int t, n, w, h, x, r, flag, ans;
cin >> t;
while (t--)
{
cin >> n >> w >> h;
for (int i = 0; i < n; i++)
{
cin >> x >> r;
l = (double)r * r - h / 2.0 * h / 2.0;
if (l < 0)
l = 0;
else l = sqrt(l);
e[i].l = x - l;
e[i].r = x + l;
}
sort(e, e + n, cmp);
flag = ans = temp = 0;
while (temp < w)
{
maxn = temp;
for (int i = 0; i < n && temp >= e[i].l; i++)
if (e[i].r > maxn)
maxn = e[i].r;
if (!(maxn - temp))
{
flag = 1;
break;
}
temp = maxn;
ans++;
}
if (flag)
cout << "0\n";
else cout << ans << endl;
}
return 0;
}