/*************************************************************
题意:给你一些点,要做一些从原点出发的射线使这些点到最近的射线的距离都不超过 d ,求最少需要做多少根射线
思路:算出每个点到与它距离不大于 d 的射线的角度的区间,然后就是区间选点的问题了,贪心
由于这是一个圈,所以要从每个开始都算一下,一个简单的方法就是把它拓展一倍
**************************************************************/
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cmath>
#include <cstring>
using namespace std;
int pn;
const double PI = acos(-1);
const double eps = 1e-9;
int cmp(double x)
{
if(x < -eps) return -1;
if(x > eps) return 1;
return 0;
}
struct Point
{
double l, r;
Point(): l(0.0), r(0.0){}
}p[777];
bool radCmp(const Point &a, const Point &b){return a.r < b.r;}
int solve()
{
double pre;
int ans = pn, t;
sort(p, p + pn, radCmp);
for (int i = 0; i < pn; i++) {
p[i + pn].l = p[i].l + 2 * PI;
p[i + pn].r = p[i].r + 2 * PI;
}
for(int i = 0; i < pn; i++)
{
int tmp = 1;
pre = p[i].r;
for(t = i + 1; t - i < pn; t++)
{
if(cmp(p[t].l - pre) > 0)
{
tmp++;
pre = p[t].r;
}
}
ans = min(ans, tmp);
}
return ans;
}
int main()
{
int T;
scanf("%d", &T);
while(T--)
{
int n, d, i, x, y;
double tmp;
scanf("%d %d", &n, &d);
pn = 0;
for(i = 0; i < n; i++)
{
scanf("%d %d", &x, &y);
int ds2 = x * x + y * y;
if(ds2 <= d * d) continue;
p[pn].l = p[pn].r = atan2(1.0 * y, 1.0 * x);
tmp = asin(1.0 * d / sqrt(1.0 * ds2));
p[pn].l -= tmp;
p[pn].r += tmp;
if(cmp(p[pn].r - PI) > 0)
{
p[pn].r -= 2 * PI;
p[pn].l -= 2 * PI;
}
pn++;
}
printf("%d\n", solve());
}
return 0;
}
uva10691 几何水题
最新推荐文章于 2020-02-01 18:16:00 发布