题目描述
在一个长 L L L 米,宽 W W W 米的草坪里装有 N N N 个浇灌喷头。
每个喷头都装在草坪中心线上 (离两边各 W 2 \frac W 2 2W 米)
我们知道每个喷头的位置 C C C (离草坪中心线左端的距离),以及它能覆盖到的浇灌范围 R R R。
请问:最少需要打开多少个喷头才能浇灌整块草坪?
输入格式
输入包含若干组测试数据。
第一行一个整数 T T T,表示数据的组数;
每组数据的第一行是整数 N N N、 L L L 和 W W W;
接下来的 行,每行包含两个整数,给出一个喷头的位置和浇灌半径 (上面的示意图是样例输入第一组数据所描述的情况)。
输出格式
对每组测试数据输出一个数字,表示为浇灌整块草坪所需喷头数目的最小值。
如果所有喷头都打开也不能浇灌整块草坪,则输出 − 1 -1 −1。
样例
样例输入
3
8 20 2
5 3
4 1
1 2
7 2
10 2
13 3
16 2
19 4
3 10 1
3 5
9 3
6 1
3 10 1
5 3
1 1
9 1样例输出
6
2
-1
数据范围
对于 100 100% 100 的数据, N < = 15000 N <= 15000 N<=15000。
提示
贪心
对于任意一个喷水装置,它能喷洒到的区域是一个已知半径的圆形。
但是喷洒到草坪上的区域,则是近似一个矩形的。
这个矩形就是圆形与草坪的四个交点所围成的矩形。 (在这里兔兔不方便画图,就需要读者自己在草稿本上画图了)
我们可以求出每个喷水装置在草坪上喷洒的区域 (之前所说的矩形) 的 左端点 和 右端点。
然后在所有左端点小于上一个区间右端点的区域中选择右端点最大的一个喷水装置。
剩下的分析,兔兔就附在代码上了哦~
下面是正解代码 (请读者不要抄袭哦~):
#include
#include
#include
using namespace std;
const int MAXN = 15005;
int T;
int N, L, W;
struct node {
double l, r;
}P[MAXN];
int cnt;
int main()
{
while (scanf("%d", &T) != EOF)
{
for (int i = 1; i <= T; i++)
{
scanf("%d %d %d", &N, &L, &W);
cnt = 0;
for (int j = 1; j <= N; j++)
{
double C, R;
scanf("%lf %lf", &C, &R);
double x = 1.0 * sqrt((1.0 * R * R) - ((W / 2.0) * (W / 2.0))); // 勾股定理, 为什么需要这样求呢? 就留给读者自己思考了哦~
if (R * 2 <= W) continue;
++cnt;
P[cnt].l = max((double)0, C - x); // 如果它的左端点超出了左边界0 , 则把它的左端点设置为左边界
P[cnt].r = min((double)L, C + x); // 如果它的右端点超出了右边界L , 则把它的右端点设置为右边界
}
int ans = 0;
double maxr = 0.0;
bool check = 0;
while (maxr < L)
{
double nowl = maxr;
for (int j = 1; j <= cnt; j++)
if (P[j].l <= nowl && P[j].r > maxr) maxr = P[j].r;
if (maxr == nowl)
{
check = 1;
break;
}
++ans;
}
if (check) printf("-1");
else printf("%d", ans);
printf("\n");
}
}
return 0;
}
如果需要兔兔改进的地方,可以在评论区留言,也可以私信兔兔哦~