您的位置:首页 > 其它

nyoj 12 喷水装置(二)

2016-07-16 17:54 309 查看


喷水装置(二)

时间限制:3000 ms | 内存限制:65535 KB
难度:4

描述有一块草坪,横向长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


解题思路:

先把二维平面问题划为一维线段问题,以线段最左端以从小到大进行排序,然后判断最右端是否大于等于草坪的长

如图:



AC代码:

# include <math.h>
# include <stdlib.h>

struct Pos
{
double left;
double right;
};

int cmp(const void * a, const void * b) //以线段的左端从小到大进行排序
{
Pos * c = (Pos *)a;
Pos * d = (Pos *)b;
return c->left > d->left ? 1 : -1;
}
int main(void)
{
int k;
scanf("%d", &k);
while (k--)
{
Pos p[10005];
int n, l, w;
int x, r;
scanf("%d %d %d", &n, &l, &w);
int i, j;
for (i = 0, j = 0; i < n; i++)
{
scanf("%d %d", &x, &r);

if (2 * r > w)
{
double dis = sqrt(r * r - (w / 2.0) * (w / 2.0)); // 此处划平面为线段 ,简化问题
p[j].left = x - dis; // 向结构体存入符合条件的喷水装置喷射的最左点的坐标
p[j].right = x + dis; // 向结构体存入符合条件的喷水装置喷射的最右点的坐标
j++;
}
}

qsort(p, j, sizeof(p[0]), cmp);
if (p[0].left > 0) // 如果最左端不能覆盖, 则输出0
{
printf("0\n");
}
else
{
double tleft = p[0].left;
double tright = p[0].right;
for (i = 0; p[i].left <= 0 && i < j; i++) // 以原点及原点以左为基点, 查找第一个有端点
{
if (p[i].right > tright)
{
tright = p[i].right;
}
}
double max;
int count = 1;
while (tright < l) // 当线段右端点小于草坪的长度时,继续执行
{

if (i >= j)
{
break;
}
max = tright;
for (; p[i].left <= tright && i < j; i++) // 以查找的第一个右为基点,继续查找最长的线段
{
if (p[i].right > max)
{
max = p[i].right;
}
}
if (tright == max)
{
break;
}
tright = max;
count ++;
}
if (tright >= l)
{
printf("%d\n", count);
}
else
{
printf("0\n");
}
}

}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息