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; }